mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-lu-20231030' of https://gitlab.com/rth7680/qemu into staging
linux-user: Fix guest signal remapping after adjusting SIGABRT linux-user: Implement VDSOs * tag 'pull-lu-20231030' of https://gitlab.com/rth7680/qemu: (21 commits) build: Add update-linux-vdso makefile rule linux-user: Show vdso address in /proc/pid/maps linux-user/s390x: Add vdso linux-user/s390x: Rename __SIGNAL_FRAMESIZE to STACK_FRAME_OVERHEAD linux-user/ppc: Add vdso linux-user/loongarch64: Add vdso linux-user/riscv: Add vdso linux-user/hppa: Add vdso linux-user/arm: Add vdso linux-user/aarch64: Add vdso linux-user/x86_64: Add vdso linux-user/i386: Add vdso linux-user: Add gen-vdso tool linux-user: Load vdso image if available linux-user: Replace bprm->fd with bprm->src.fd linux-user: Use ImageSource in load_symbols linux-user: Use ImageSource in load_elf_image linux-user: Do not clobber bprm_buf swapping ehdr linux-user: Tidy loader_exec linux-user: Introduce imgsrc_read, imgsrc_read_alloc ... Conflicts: linux-user/arm/signal.c Fix an #include context conflict. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
@@ -283,6 +283,13 @@ include $(SRC_PATH)/tests/vm/Makefile.include
|
||||
print-help-run = printf " %-30s - %s\\n" "$1" "$2"
|
||||
print-help = @$(call print-help-run,$1,$2)
|
||||
|
||||
.PHONY: update-linux-vdso
|
||||
update-linux-vdso:
|
||||
@for m in $(SRC_PATH)/linux-user/*/Makefile.vdso; do \
|
||||
$(MAKE) $(SUBDIR_MAKEFLAGS) -C $$(dirname $$m) -f Makefile.vdso \
|
||||
SRC_PATH=$(SRC_PATH) BUILD_DIR=$(BUILD_DIR); \
|
||||
done
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo 'Generic targets:'
|
||||
@@ -303,6 +310,9 @@ endif
|
||||
$(call print-help,distclean,Remove all generated files)
|
||||
$(call print-help,dist,Build a distributable tarball)
|
||||
@echo ''
|
||||
@echo 'Linux-user targets:'
|
||||
$(call print-help,update-linux-vdso,Build linux-user vdso images)
|
||||
@echo ''
|
||||
@echo 'Test targets:'
|
||||
$(call print-help,check,Run all tests (check-help for details))
|
||||
$(call print-help,bench,Run all benchmarks)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
include $(BUILD_DIR)/tests/tcg/aarch64-linux-user/config-target.mak
|
||||
|
||||
SUBDIR = $(SRC_PATH)/linux-user/aarch64
|
||||
VPATH += $(SUBDIR)
|
||||
|
||||
all: $(SUBDIR)/vdso-be.so $(SUBDIR)/vdso-le.so
|
||||
|
||||
LDFLAGS = -nostdlib -shared -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
|
||||
$(CC) -o $@ $(LDFLAGS) -mbig-endian $<
|
||||
|
||||
$(SUBDIR)/vdso-le.so: vdso.S vdso.ld
|
||||
$(CC) -o $@ $(LDFLAGS) -mlittle-endian $<
|
||||
@@ -0,0 +1,11 @@
|
||||
# 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: ['-r', '__kernel_rt_sigreturn'])
|
||||
|
||||
vdso_le_inc = gen_vdso.process('vdso-le.so',
|
||||
extra_args: ['-r', '__kernel_rt_sigreturn'])
|
||||
|
||||
linux_user_ss.add(when: 'TARGET_AARCH64', if_true: [vdso_be_inc, vdso_le_inc])
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* aarch64 linux replacement vdso.
|
||||
*
|
||||
* Copyright 2023 Linaro, Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <asm/unistd.h>
|
||||
|
||||
/* ??? These are in include/elf.h, which is not ready for inclusion in asm. */
|
||||
#define NT_GNU_PROPERTY_TYPE_0 5
|
||||
#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
|
||||
#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1U << 0)
|
||||
#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1U << 1)
|
||||
|
||||
#define GNU_PROPERTY_AARCH64_FEATURE_1_DEFAULT \
|
||||
(GNU_PROPERTY_AARCH64_FEATURE_1_BTI | GNU_PROPERTY_AARCH64_FEATURE_1_PAC)
|
||||
|
||||
.section .note.gnu.property
|
||||
.align 3
|
||||
.long 2f - 1f
|
||||
.long 6f - 3f
|
||||
.long NT_GNU_PROPERTY_TYPE_0
|
||||
1: .string "GNU"
|
||||
2: .align 3
|
||||
3: .long GNU_PROPERTY_AARCH64_FEATURE_1_AND
|
||||
.long 5f - 4f
|
||||
4: .long GNU_PROPERTY_AARCH64_FEATURE_1_DEFAULT
|
||||
5: .align 3
|
||||
6:
|
||||
|
||||
.text
|
||||
|
||||
.macro endf name
|
||||
.globl \name
|
||||
.type \name, @function
|
||||
.size \name, . - \name
|
||||
.endm
|
||||
|
||||
.macro vdso_syscall name, nr
|
||||
\name:
|
||||
bti c
|
||||
mov x8, #\nr
|
||||
svc #0
|
||||
ret
|
||||
endf \name
|
||||
.endm
|
||||
|
||||
.cfi_startproc
|
||||
|
||||
vdso_syscall __kernel_gettimeofday, __NR_gettimeofday
|
||||
vdso_syscall __kernel_clock_gettime, __NR_clock_gettime
|
||||
vdso_syscall __kernel_clock_getres, __NR_clock_getres
|
||||
|
||||
.cfi_endproc
|
||||
|
||||
|
||||
/*
|
||||
* TODO: The kernel makes a big deal of turning off the .cfi directives,
|
||||
* because they cause libgcc to crash, but that's because they're wrong.
|
||||
*
|
||||
* For now, elide the unwind info for __kernel_rt_sigreturn and rely on
|
||||
* the libgcc fallback routine as we have always done. This requires
|
||||
* that the code sequence used be exact.
|
||||
*/
|
||||
__kernel_rt_sigreturn:
|
||||
/* No BTI C insn here -- we arrive via RET. */
|
||||
mov x8, #__NR_rt_sigreturn
|
||||
svc #0
|
||||
endf __kernel_rt_sigreturn
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Linker script for linux aarch64 replacement vdso.
|
||||
*
|
||||
* Copyright 2021 Linaro, Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
VERSION {
|
||||
LINUX_2.6.39 {
|
||||
global:
|
||||
__kernel_rt_sigreturn;
|
||||
__kernel_gettimeofday;
|
||||
__kernel_clock_gettime;
|
||||
__kernel_clock_getres;
|
||||
|
||||
local: *;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
PHDRS {
|
||||
phdr PT_PHDR FLAGS(4) PHDRS;
|
||||
load PT_LOAD FLAGS(7) FILEHDR PHDRS;
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
eh_frame_hdr PT_GNU_EH_FRAME;
|
||||
note PT_NOTE FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS {
|
||||
/*
|
||||
* We can't prelink to any address without knowing something about
|
||||
* the virtual memory space of the host, since that leaks over into
|
||||
* the available memory space of the guest.
|
||||
*/
|
||||
. = 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 =0xd503201f
|
||||
}
|
||||
@@ -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])
|
||||
|
||||
+35
-20
@@ -22,6 +22,7 @@
|
||||
#include "signal-common.h"
|
||||
#include "linux-user/trace.h"
|
||||
#include "target/arm/cpu-features.h"
|
||||
#include "vdso-asmoffset.h"
|
||||
|
||||
struct target_sigcontext {
|
||||
abi_ulong trap_no;
|
||||
@@ -103,6 +104,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;
|
||||
|
||||
/*
|
||||
@@ -161,6 +167,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)
|
||||
@@ -168,9 +177,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
|
||||
@@ -185,9 +194,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);
|
||||
|
||||
@@ -203,24 +210,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;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
/* offsetof(struct sigframe, retcode[3]) */
|
||||
#define SIGFRAME_RC3_OFFSET 756
|
||||
#define RT_SIGFRAME_RC3_OFFSET 884
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
+226
-133
File diff suppressed because it is too large
Load Diff
@@ -463,7 +463,7 @@ static int load_flat_file(struct linux_binprm * bprm,
|
||||
DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
|
||||
|
||||
textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
|
||||
MAP_PRIVATE, bprm->fd, 0);
|
||||
MAP_PRIVATE, bprm->src.fd, 0);
|
||||
if (textpos == -1) {
|
||||
fprintf(stderr, "Unable to mmap process text\n");
|
||||
return -1;
|
||||
@@ -490,7 +490,7 @@ static int load_flat_file(struct linux_binprm * bprm,
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
result = target_pread(bprm->fd, datapos,
|
||||
result = target_pread(bprm->src.fd, datapos,
|
||||
data_len + (relocs * sizeof(abi_ulong)),
|
||||
fpos);
|
||||
}
|
||||
@@ -540,10 +540,10 @@ static int load_flat_file(struct linux_binprm * bprm,
|
||||
else
|
||||
#endif
|
||||
{
|
||||
result = target_pread(bprm->fd, textpos,
|
||||
result = target_pread(bprm->src.fd, textpos,
|
||||
text_len, 0);
|
||||
if (result >= 0) {
|
||||
result = target_pread(bprm->fd, datapos,
|
||||
result = target_pread(bprm->src.fd, datapos,
|
||||
data_len + (relocs * sizeof(abi_ulong)),
|
||||
ntohl(hdr->data_start));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Post-process a vdso elf image for inclusion into qemu.
|
||||
* Elf size specialization.
|
||||
*
|
||||
* Copyright 2023 Linaro, Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
static void elfN(bswap_ehdr)(ElfN(Ehdr) *ehdr)
|
||||
{
|
||||
bswaps(&ehdr->e_type); /* Object file type */
|
||||
bswaps(&ehdr->e_machine); /* Architecture */
|
||||
bswaps(&ehdr->e_version); /* Object file version */
|
||||
bswaps(&ehdr->e_entry); /* Entry point virtual address */
|
||||
bswaps(&ehdr->e_phoff); /* Program header table file offset */
|
||||
bswaps(&ehdr->e_shoff); /* Section header table file offset */
|
||||
bswaps(&ehdr->e_flags); /* Processor-specific flags */
|
||||
bswaps(&ehdr->e_ehsize); /* ELF header size in bytes */
|
||||
bswaps(&ehdr->e_phentsize); /* Program header table entry size */
|
||||
bswaps(&ehdr->e_phnum); /* Program header table entry count */
|
||||
bswaps(&ehdr->e_shentsize); /* Section header table entry size */
|
||||
bswaps(&ehdr->e_shnum); /* Section header table entry count */
|
||||
bswaps(&ehdr->e_shstrndx); /* Section header string table index */
|
||||
}
|
||||
|
||||
static void elfN(bswap_phdr)(ElfN(Phdr) *phdr)
|
||||
{
|
||||
bswaps(&phdr->p_type); /* Segment type */
|
||||
bswaps(&phdr->p_flags); /* Segment flags */
|
||||
bswaps(&phdr->p_offset); /* Segment file offset */
|
||||
bswaps(&phdr->p_vaddr); /* Segment virtual address */
|
||||
bswaps(&phdr->p_paddr); /* Segment physical address */
|
||||
bswaps(&phdr->p_filesz); /* Segment size in file */
|
||||
bswaps(&phdr->p_memsz); /* Segment size in memory */
|
||||
bswaps(&phdr->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
static void elfN(bswap_shdr)(ElfN(Shdr) *shdr)
|
||||
{
|
||||
bswaps(&shdr->sh_name);
|
||||
bswaps(&shdr->sh_type);
|
||||
bswaps(&shdr->sh_flags);
|
||||
bswaps(&shdr->sh_addr);
|
||||
bswaps(&shdr->sh_offset);
|
||||
bswaps(&shdr->sh_size);
|
||||
bswaps(&shdr->sh_link);
|
||||
bswaps(&shdr->sh_info);
|
||||
bswaps(&shdr->sh_addralign);
|
||||
bswaps(&shdr->sh_entsize);
|
||||
}
|
||||
|
||||
static void elfN(bswap_sym)(ElfN(Sym) *sym)
|
||||
{
|
||||
bswaps(&sym->st_name);
|
||||
bswaps(&sym->st_value);
|
||||
bswaps(&sym->st_size);
|
||||
bswaps(&sym->st_shndx);
|
||||
}
|
||||
|
||||
static void elfN(bswap_dyn)(ElfN(Dyn) *dyn)
|
||||
{
|
||||
bswaps(&dyn->d_tag); /* Dynamic type tag */
|
||||
bswaps(&dyn->d_un.d_ptr); /* Dynamic ptr or val, in union */
|
||||
}
|
||||
|
||||
static void elfN(search_symtab)(ElfN(Shdr) *shdr, unsigned sym_idx,
|
||||
void *buf, bool need_bswap)
|
||||
{
|
||||
unsigned str_idx = shdr[sym_idx].sh_link;
|
||||
ElfN(Sym) *sym = buf + shdr[sym_idx].sh_offset;
|
||||
unsigned sym_n = shdr[sym_idx].sh_size / sizeof(*sym);
|
||||
const char *str = buf + shdr[str_idx].sh_offset;
|
||||
|
||||
for (unsigned i = 0; i < sym_n; ++i) {
|
||||
const char *name;
|
||||
|
||||
if (need_bswap) {
|
||||
elfN(bswap_sym)(sym + i);
|
||||
}
|
||||
name = str + sym[i].st_name;
|
||||
|
||||
if (sigreturn_sym && strcmp(sigreturn_sym, name) == 0) {
|
||||
sigreturn_addr = sym[i].st_value;
|
||||
}
|
||||
if (rt_sigreturn_sym && strcmp(rt_sigreturn_sym, name) == 0) {
|
||||
rt_sigreturn_addr = sym[i].st_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
||||
{
|
||||
ElfN(Ehdr) *ehdr = buf;
|
||||
ElfN(Phdr) *phdr;
|
||||
ElfN(Shdr) *shdr;
|
||||
unsigned phnum, shnum;
|
||||
unsigned dynamic_ofs = 0;
|
||||
unsigned dynamic_addr = 0;
|
||||
unsigned symtab_idx = 0;
|
||||
unsigned dynsym_idx = 0;
|
||||
unsigned first_segsz = 0;
|
||||
int errors = 0;
|
||||
|
||||
if (need_bswap) {
|
||||
elfN(bswap_ehdr)(ehdr);
|
||||
}
|
||||
|
||||
phnum = ehdr->e_phnum;
|
||||
phdr = buf + ehdr->e_phoff;
|
||||
if (need_bswap) {
|
||||
for (unsigned i = 0; i < phnum; ++i) {
|
||||
elfN(bswap_phdr)(phdr + i);
|
||||
}
|
||||
}
|
||||
|
||||
shnum = ehdr->e_shnum;
|
||||
shdr = buf + ehdr->e_shoff;
|
||||
if (need_bswap) {
|
||||
for (unsigned i = 0; i < shnum; ++i) {
|
||||
elfN(bswap_shdr)(shdr + i);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < shnum; ++i) {
|
||||
switch (shdr[i].sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
symtab_idx = i;
|
||||
break;
|
||||
case SHT_DYNSYM:
|
||||
dynsym_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the VDSO is created as we expect: that PT_PHDR,
|
||||
* PT_DYNAMIC, and PT_NOTE located in a writable data segment.
|
||||
* PHDR and DYNAMIC require relocation, and NOTE will get the
|
||||
* linux version number.
|
||||
*/
|
||||
for (unsigned i = 0; i < phnum; ++i) {
|
||||
if (phdr[i].p_type != PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
if (first_segsz != 0) {
|
||||
fprintf(stderr, "Multiple LOAD segments\n");
|
||||
errors++;
|
||||
}
|
||||
if (phdr[i].p_offset != 0) {
|
||||
fprintf(stderr, "LOAD segment does not cover EHDR\n");
|
||||
errors++;
|
||||
}
|
||||
if (phdr[i].p_vaddr != 0) {
|
||||
fprintf(stderr, "LOAD segment not loaded at address 0\n");
|
||||
errors++;
|
||||
}
|
||||
first_segsz = phdr[i].p_filesz;
|
||||
if (first_segsz < ehdr->e_phoff + phnum * sizeof(*phdr)) {
|
||||
fprintf(stderr, "LOAD segment does not cover PHDRs\n");
|
||||
errors++;
|
||||
}
|
||||
if ((phdr[i].p_flags & (PF_R | PF_W)) != (PF_R | PF_W)) {
|
||||
fprintf(stderr, "LOAD segment is not read-write\n");
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < phnum; ++i) {
|
||||
const char *which;
|
||||
|
||||
switch (phdr[i].p_type) {
|
||||
case PT_PHDR:
|
||||
which = "PT_PHDR";
|
||||
break;
|
||||
case PT_NOTE:
|
||||
which = "PT_NOTE";
|
||||
break;
|
||||
case PT_DYNAMIC:
|
||||
dynamic_ofs = phdr[i].p_offset;
|
||||
dynamic_addr = phdr[i].p_vaddr;
|
||||
which = "PT_DYNAMIC";
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (first_segsz < phdr[i].p_vaddr + phdr[i].p_filesz) {
|
||||
fprintf(stderr, "LOAD segment does not cover %s\n", which);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (errors) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Relocate the program headers. */
|
||||
for (unsigned i = 0; i < phnum; ++i) {
|
||||
output_reloc(outf, buf, &phdr[i].p_vaddr);
|
||||
output_reloc(outf, buf, &phdr[i].p_paddr);
|
||||
}
|
||||
|
||||
/* Relocate the DYNAMIC entries. */
|
||||
if (dynamic_addr) {
|
||||
ElfN(Dyn) *dyn = buf + dynamic_ofs;
|
||||
__typeof(dyn->d_tag) tag;
|
||||
|
||||
do {
|
||||
|
||||
if (need_bswap) {
|
||||
elfN(bswap_dyn)(dyn);
|
||||
}
|
||||
tag = dyn->d_tag;
|
||||
|
||||
switch (tag) {
|
||||
case DT_HASH:
|
||||
case DT_SYMTAB:
|
||||
case DT_STRTAB:
|
||||
case DT_VERDEF:
|
||||
case DT_VERSYM:
|
||||
case DT_PLTGOT:
|
||||
case DT_ADDRRNGLO ... DT_ADDRRNGHI:
|
||||
/* These entries store an address in the entry. */
|
||||
output_reloc(outf, buf, &dyn->d_un.d_val);
|
||||
break;
|
||||
|
||||
case DT_NULL:
|
||||
case DT_STRSZ:
|
||||
case DT_SONAME:
|
||||
case DT_DEBUG:
|
||||
case DT_FLAGS:
|
||||
case DT_FLAGS_1:
|
||||
case DT_SYMBOLIC:
|
||||
case DT_BIND_NOW:
|
||||
case DT_VERDEFNUM:
|
||||
case DT_VALRNGLO ... DT_VALRNGHI:
|
||||
/* These entries store an integer in the entry. */
|
||||
break;
|
||||
|
||||
case DT_SYMENT:
|
||||
if (dyn->d_un.d_val != sizeof(ElfN(Sym))) {
|
||||
fprintf(stderr, "VDSO has incorrect dynamic symbol size\n");
|
||||
errors++;
|
||||
}
|
||||
break;
|
||||
|
||||
case DT_REL:
|
||||
case DT_RELSZ:
|
||||
case DT_RELA:
|
||||
case DT_RELASZ:
|
||||
/*
|
||||
* These entries indicate that the VDSO was built incorrectly.
|
||||
* It should not have any real relocations.
|
||||
* ??? The RISC-V toolchain will emit these even when there
|
||||
* are no relocations. Validate zeros.
|
||||
*/
|
||||
if (dyn->d_un.d_val != 0) {
|
||||
fprintf(stderr, "VDSO has dynamic relocations\n");
|
||||
errors++;
|
||||
}
|
||||
break;
|
||||
case DT_RELENT:
|
||||
case DT_RELAENT:
|
||||
case DT_TEXTREL:
|
||||
/* These entries store an integer in the entry. */
|
||||
/* Should not be required; see above. */
|
||||
break;
|
||||
|
||||
case DT_NEEDED:
|
||||
case DT_VERNEED:
|
||||
case DT_PLTREL:
|
||||
case DT_JMPREL:
|
||||
case DT_RPATH:
|
||||
case DT_RUNPATH:
|
||||
fprintf(stderr, "VDSO has external dependencies\n");
|
||||
errors++;
|
||||
break;
|
||||
|
||||
case PT_LOPROC + 3:
|
||||
if (ehdr->e_machine == EM_PPC64) {
|
||||
break; /* DT_PPC64_OPT: integer bitmask */
|
||||
}
|
||||
goto do_default;
|
||||
|
||||
default:
|
||||
do_default:
|
||||
/* This is probably something target specific. */
|
||||
fprintf(stderr, "VDSO has unknown DYNAMIC entry (%lx)\n",
|
||||
(unsigned long)tag);
|
||||
errors++;
|
||||
break;
|
||||
}
|
||||
dyn++;
|
||||
} while (tag != DT_NULL);
|
||||
if (errors) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Relocate the dynamic symbol table. */
|
||||
if (dynsym_idx) {
|
||||
ElfN(Sym) *sym = buf + shdr[dynsym_idx].sh_offset;
|
||||
unsigned sym_n = shdr[dynsym_idx].sh_size / sizeof(*sym);
|
||||
|
||||
for (unsigned i = 0; i < sym_n; ++i) {
|
||||
output_reloc(outf, buf, &sym[i].st_value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Search both dynsym and symtab for the signal return symbols. */
|
||||
if (dynsym_idx) {
|
||||
elfN(search_symtab)(shdr, dynsym_idx, buf, need_bswap);
|
||||
}
|
||||
if (symtab_idx) {
|
||||
elfN(search_symtab)(shdr, symtab_idx, buf, need_bswap);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Post-process a vdso elf image for inclusion into qemu.
|
||||
*
|
||||
* Copyright 2023 Linaro, Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <endian.h>
|
||||
#include <unistd.h>
|
||||
#include "elf.h"
|
||||
|
||||
|
||||
#define bswap_(p) _Generic(*(p), \
|
||||
uint16_t: __builtin_bswap16, \
|
||||
uint32_t: __builtin_bswap32, \
|
||||
uint64_t: __builtin_bswap64, \
|
||||
int16_t: __builtin_bswap16, \
|
||||
int32_t: __builtin_bswap32, \
|
||||
int64_t: __builtin_bswap64)
|
||||
#define bswaps(p) (*(p) = bswap_(p)(*(p)))
|
||||
|
||||
static void output_reloc(FILE *outf, void *buf, void *loc)
|
||||
{
|
||||
fprintf(outf, " 0x%08tx,\n", loc - buf);
|
||||
}
|
||||
|
||||
static const char *sigreturn_sym;
|
||||
static const char *rt_sigreturn_sym;
|
||||
|
||||
static unsigned sigreturn_addr;
|
||||
static unsigned rt_sigreturn_addr;
|
||||
|
||||
#define N 32
|
||||
#define elfN(x) elf32_##x
|
||||
#define ElfN(x) Elf32_##x
|
||||
#include "gen-vdso-elfn.c.inc"
|
||||
#undef N
|
||||
#undef elfN
|
||||
#undef ElfN
|
||||
|
||||
#define N 64
|
||||
#define elfN(x) elf64_##x
|
||||
#define ElfN(x) Elf64_##x
|
||||
#include "gen-vdso-elfn.c.inc"
|
||||
#undef N
|
||||
#undef elfN
|
||||
#undef ElfN
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *inf, *outf;
|
||||
long total_len;
|
||||
const char *prefix = "vdso";
|
||||
const char *inf_name;
|
||||
const char *outf_name = NULL;
|
||||
unsigned char *buf;
|
||||
bool need_bswap;
|
||||
|
||||
while (1) {
|
||||
int opt = getopt(argc, argv, "o:p:r:s:");
|
||||
if (opt < 0) {
|
||||
break;
|
||||
}
|
||||
switch (opt) {
|
||||
case 'o':
|
||||
outf_name = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
prefix = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
rt_sigreturn_sym = optarg;
|
||||
break;
|
||||
case 's':
|
||||
sigreturn_sym = optarg;
|
||||
break;
|
||||
default:
|
||||
usage:
|
||||
fprintf(stderr, "usage: [-p prefix] [-r rt-sigreturn-name] "
|
||||
"[-s sigreturn-name] -o output-file input-file\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc || outf_name == NULL) {
|
||||
goto usage;
|
||||
}
|
||||
inf_name = argv[optind];
|
||||
|
||||
/*
|
||||
* Open the input and output files.
|
||||
*/
|
||||
inf = fopen(inf_name, "rb");
|
||||
if (inf == NULL) {
|
||||
goto perror_inf;
|
||||
}
|
||||
outf = fopen(outf_name, "w");
|
||||
if (outf == NULL) {
|
||||
goto perror_outf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the input file into a buffer.
|
||||
* We expect the vdso to be small, on the order of one page,
|
||||
* therefore we do not expect a partial read.
|
||||
*/
|
||||
fseek(inf, 0, SEEK_END);
|
||||
total_len = ftell(inf);
|
||||
fseek(inf, 0, SEEK_SET);
|
||||
|
||||
buf = malloc(total_len);
|
||||
if (buf == NULL) {
|
||||
goto perror_inf;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (fread(buf, 1, total_len, inf) != total_len) {
|
||||
if (errno) {
|
||||
goto perror_inf;
|
||||
}
|
||||
fprintf(stderr, "%s: incomplete read\n", inf_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fclose(inf);
|
||||
|
||||
/*
|
||||
* Write out the vdso image now, before we make local changes.
|
||||
*/
|
||||
|
||||
fprintf(outf,
|
||||
"/* Automatically generated from linux-user/gen-vdso.c. */\n"
|
||||
"\n"
|
||||
"static const uint8_t %s_image[] = {",
|
||||
prefix);
|
||||
for (long i = 0; i < total_len; ++i) {
|
||||
if (i % 12 == 0) {
|
||||
fputs("\n ", outf);
|
||||
}
|
||||
fprintf(outf, " 0x%02x,", buf[i]);
|
||||
}
|
||||
fprintf(outf, "\n};\n\n");
|
||||
|
||||
/*
|
||||
* Identify which elf flavor we're processing.
|
||||
* The first 16 bytes of the file are e_ident.
|
||||
*/
|
||||
|
||||
if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1 ||
|
||||
buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) {
|
||||
fprintf(stderr, "%s: not an elf file\n", inf_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
switch (buf[EI_DATA]) {
|
||||
case ELFDATA2LSB:
|
||||
need_bswap = BYTE_ORDER != LITTLE_ENDIAN;
|
||||
break;
|
||||
case ELFDATA2MSB:
|
||||
need_bswap = BYTE_ORDER != BIG_ENDIAN;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: invalid elf EI_DATA (%u)\n",
|
||||
inf_name, buf[EI_DATA]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to relocate the VDSO image. The one built into the kernel
|
||||
* is built for a fixed address. The one we built for QEMU is not,
|
||||
* since that requires close control of the guest address space.
|
||||
*
|
||||
* Output relocation addresses as we go.
|
||||
*/
|
||||
|
||||
fprintf(outf, "static const unsigned %s_relocs[] = {\n", prefix);
|
||||
|
||||
switch (buf[EI_CLASS]) {
|
||||
case ELFCLASS32:
|
||||
elf32_process(outf, buf, need_bswap);
|
||||
break;
|
||||
case ELFCLASS64:
|
||||
elf64_process(outf, buf, need_bswap);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: invalid elf EI_CLASS (%u)\n",
|
||||
inf_name, buf[EI_CLASS]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fprintf(outf, "};\n\n"); /* end vdso_relocs. */
|
||||
|
||||
fprintf(outf, "static const VdsoImageInfo %s_image_info = {\n", prefix);
|
||||
fprintf(outf, " .image = %s_image,\n", prefix);
|
||||
fprintf(outf, " .relocs = %s_relocs,\n", prefix);
|
||||
fprintf(outf, " .image_size = sizeof(%s_image),\n", prefix);
|
||||
fprintf(outf, " .reloc_count = ARRAY_SIZE(%s_relocs),\n", prefix);
|
||||
fprintf(outf, " .sigreturn_ofs = 0x%x,\n", sigreturn_addr);
|
||||
fprintf(outf, " .rt_sigreturn_ofs = 0x%x,\n", rt_sigreturn_addr);
|
||||
fprintf(outf, "};\n");
|
||||
|
||||
/*
|
||||
* Everything should have gone well.
|
||||
*/
|
||||
if (fclose(outf)) {
|
||||
goto perror_outf;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
perror_inf:
|
||||
perror(inf_name);
|
||||
return EXIT_FAILURE;
|
||||
|
||||
perror_outf:
|
||||
perror(outf_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
include $(BUILD_DIR)/tests/tcg/hppa-linux-user/config-target.mak
|
||||
|
||||
SUBDIR = $(SRC_PATH)/linux-user/hppa
|
||||
VPATH += $(SUBDIR)
|
||||
|
||||
all: $(SUBDIR)/vdso.so
|
||||
|
||||
$(SUBDIR)/vdso.so: vdso.S vdso.ld vdso-asmoffset.h
|
||||
$(CC) -o $@ -nostdlib -shared -Wl,-h,linux-vdso32.so.1 \
|
||||
-Wl,--build-id=sha1 -Wl,--hash-style=both \
|
||||
-Wl,-T,$(SUBDIR)/vdso.ld $<
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user