Add helper binary `exec1'
* .gitignore: New files.
* Makefile.in (mostlyclean_dirs): Add libexec, if its Makefile
exists.
* autogen.sh (do_git): Autoreconf in exec as well.
* configure.ac: Configure libexec on Android.
* exec/Makefile.in:
* exec/README:
* exec/config-mips.m4.in:
* exec/config.guess:
* exec/config.h.in:
* exec/config.sub:
* exec/configure:
* exec/configure.ac:
* exec/deps.mk:
* exec/exec.c (MIN, struct exec_open_command)
(struct exec_map_command, struct exec_jump_command)
(write_open_command, write_load_command, process_interpreter_1)
(process_interpreter, process_program_header, insert_args)
(exec_0):
* exec/exec.h (_EXEC_H_, struct elf_header_32)
(struct program_header_32, struct dt_entry_32)
(struct elf_header_64, struct program_header_64)
(struct dt_entry_64, struct exec_tracee):
* exec/exec1.c (main):
* exec/install-sh (scriptversion):
* exec/loader-aarch64.s (_start):
* exec/loader-armeabi.s (_start):
* exec/loader-mips64el.s (__start):
* exec/loader-mipsel.s (__start):
* exec/loader-x86.s (_start):
* exec/loader-x86_64.s (_start):
* exec/mipsel-user.h (_MIPSEL_USER_H_):
* exec/mipsfpu.c (MIPS_ABI_FP_ANY, fpu_reqs, valid_abi_p)
(fp_mode_for_abi, cpu_supports_fr0_p, determine_fpu_mode):
* exec/mipsfpu.h (_MIPSFPU_H_, FP_FR0):
* exec/test.c (print_usage, main):
* exec/trace.c (MAX_TRACEES, aarch64_set_regs, read_memory)
(user_alloca, user_copy, remove_tracee, handle_clone)
(syscall_trap_p, handle_exec, process_system_call, tracing_execve)
(after_fork, find_tracee, exec_waitpid, exec_init): New files.
* java/Makefile.in (CROSS_EXEC_BINS): Add exec1 and
loader.
($(CROSS_EXEC_BINS) &): New target.
2023-04-30 21:37:19 +08:00
|
|
|
|
/* Program execution for Emacs.
|
|
|
|
|
|
2024-01-02 10:30:05 +08:00
|
|
|
|
Copyright (C) 2023-2024 Free Software Foundation, Inc.
|
Add helper binary `exec1'
* .gitignore: New files.
* Makefile.in (mostlyclean_dirs): Add libexec, if its Makefile
exists.
* autogen.sh (do_git): Autoreconf in exec as well.
* configure.ac: Configure libexec on Android.
* exec/Makefile.in:
* exec/README:
* exec/config-mips.m4.in:
* exec/config.guess:
* exec/config.h.in:
* exec/config.sub:
* exec/configure:
* exec/configure.ac:
* exec/deps.mk:
* exec/exec.c (MIN, struct exec_open_command)
(struct exec_map_command, struct exec_jump_command)
(write_open_command, write_load_command, process_interpreter_1)
(process_interpreter, process_program_header, insert_args)
(exec_0):
* exec/exec.h (_EXEC_H_, struct elf_header_32)
(struct program_header_32, struct dt_entry_32)
(struct elf_header_64, struct program_header_64)
(struct dt_entry_64, struct exec_tracee):
* exec/exec1.c (main):
* exec/install-sh (scriptversion):
* exec/loader-aarch64.s (_start):
* exec/loader-armeabi.s (_start):
* exec/loader-mips64el.s (__start):
* exec/loader-mipsel.s (__start):
* exec/loader-x86.s (_start):
* exec/loader-x86_64.s (_start):
* exec/mipsel-user.h (_MIPSEL_USER_H_):
* exec/mipsfpu.c (MIPS_ABI_FP_ANY, fpu_reqs, valid_abi_p)
(fp_mode_for_abi, cpu_supports_fr0_p, determine_fpu_mode):
* exec/mipsfpu.h (_MIPSFPU_H_, FP_FR0):
* exec/test.c (print_usage, main):
* exec/trace.c (MAX_TRACEES, aarch64_set_regs, read_memory)
(user_alloca, user_copy, remove_tracee, handle_clone)
(syscall_trap_p, handle_exec, process_system_call, tracing_execve)
(after_fork, find_tracee, exec_waitpid, exec_init): New files.
* java/Makefile.in (CROSS_EXEC_BINS): Add exec1 and
loader.
($(CROSS_EXEC_BINS) &): New target.
2023-04-30 21:37:19 +08:00
|
|
|
|
|
|
|
|
|
This file is part of GNU Emacs.
|
|
|
|
|
|
|
|
|
|
GNU Emacs is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or (at
|
|
|
|
|
your option) any later version.
|
|
|
|
|
|
|
|
|
|
GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#include "mipsfpu.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* OABI MIPS systems support several different modes of execution.
|
|
|
|
|
Each mode differs in the size and utilization of the hardware
|
|
|
|
|
floating-point registers.
|
|
|
|
|
|
|
|
|
|
Linux normally sets the floating point mode to one appropriate for
|
|
|
|
|
execution, taking into account the floating point modes of the
|
|
|
|
|
interpreter and executable binaries. However, this logic is
|
|
|
|
|
forsaken when the `execve' system call is overwritten.
|
|
|
|
|
|
|
|
|
|
Thus, the correct floating point mode must be determined and set
|
|
|
|
|
within the loader binary. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Various constants used throughout this code. */
|
|
|
|
|
|
|
|
|
|
#define MIPS_ABI_FP_ANY 0 /* FP ABI doesn't matter */
|
|
|
|
|
#define MIPS_ABI_FP_DOUBLE 1 /* -mdouble-float */
|
|
|
|
|
#define MIPS_ABI_FP_SINGLE 2 /* -msingle-float */
|
|
|
|
|
#define MIPS_ABI_FP_SOFT 3 /* -msoft-float */
|
|
|
|
|
#define MIPS_ABI_FP_OLD_64 4 /* -mips32r2 -mfp64 */
|
|
|
|
|
#define MIPS_ABI_FP_XX 5 /* -mfpxx */
|
|
|
|
|
#define MIPS_ABI_FP_64 6 /* -mips32r2 -mfp64 */
|
|
|
|
|
#define MIPS_ABI_FP_64A 7 /* -mips32r2 -mfp64 -mno-odd-spreg */
|
|
|
|
|
|
|
|
|
|
#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */
|
|
|
|
|
#define EF_MIPS_PIC 2 /* Contains PIC code. */
|
|
|
|
|
#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */
|
|
|
|
|
#define EF_MIPS_XGOT 8
|
|
|
|
|
#define EF_MIPS_64BIT_WHIRL 16
|
|
|
|
|
#define EF_MIPS_ABI2 32
|
|
|
|
|
#define EF_MIPS_ABI_ON32 64
|
|
|
|
|
#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */
|
|
|
|
|
#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
|
|
|
|
|
#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Structure describing the requirements of a single floating-point
|
|
|
|
|
ABI. */
|
|
|
|
|
|
|
|
|
|
struct mode_description
|
|
|
|
|
{
|
|
|
|
|
/* Whether or not the ABI only executes single precision
|
|
|
|
|
instructions, and can operate in both 32-bit or 64-bit floating
|
|
|
|
|
point mode. */
|
|
|
|
|
bool single;
|
|
|
|
|
|
|
|
|
|
/* Whether or not the ABI performs floating point operations in
|
|
|
|
|
software, using integer registers. */
|
|
|
|
|
bool soft;
|
|
|
|
|
|
|
|
|
|
/* Whether or not the ABI requires the use of 64-bit floating point
|
|
|
|
|
registers. */
|
|
|
|
|
bool fr1;
|
|
|
|
|
|
|
|
|
|
/* Whether or not the ABI requires the use of 64-bit floating point
|
|
|
|
|
registers on NABI systems, and 32-bit ones on OABI systems. */
|
|
|
|
|
bool frdefault;
|
|
|
|
|
|
|
|
|
|
/* Whether or not this ABI requires single precision floating point
|
|
|
|
|
emulation. */
|
|
|
|
|
bool fre;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct mode_description fpu_reqs[] =
|
|
|
|
|
{
|
|
|
|
|
[MIPS_ABI_FP_ANY] = { true, true, true, true, true, },
|
|
|
|
|
[MIPS_ABI_FP_DOUBLE] = { false, false, false, true, true, },
|
|
|
|
|
[MIPS_ABI_FP_SINGLE] = { true, false, false, false, false, },
|
|
|
|
|
[MIPS_ABI_FP_SOFT] = { false, true, false, false, false, },
|
|
|
|
|
[MIPS_ABI_FP_OLD_64] = { false, false, false, false, false, },
|
|
|
|
|
[MIPS_ABI_FP_XX] = { false, false, true, true, true, },
|
|
|
|
|
[MIPS_ABI_FP_64] = { false, false, true, false, false, },
|
|
|
|
|
[MIPS_ABI_FP_64A] = { false, false, true, false, true, },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Return whether or not the given floating-point ABI is valid. */
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
valid_abi_p (int abi)
|
|
|
|
|
{
|
|
|
|
|
switch (abi)
|
|
|
|
|
{
|
|
|
|
|
case MIPS_ABI_FP_ANY:
|
|
|
|
|
case MIPS_ABI_FP_DOUBLE:
|
|
|
|
|
case MIPS_ABI_FP_SINGLE:
|
|
|
|
|
case MIPS_ABI_FP_SOFT:
|
|
|
|
|
case MIPS_ABI_FP_OLD_64:
|
|
|
|
|
case MIPS_ABI_FP_XX:
|
|
|
|
|
case MIPS_ABI_FP_64:
|
|
|
|
|
case MIPS_ABI_FP_64A:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the floating point mode appropriate for the specified
|
|
|
|
|
floating point ABI. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
fp_mode_for_abi (int abi)
|
|
|
|
|
{
|
|
|
|
|
struct mode_description *desc;
|
|
|
|
|
|
|
|
|
|
desc = &fpu_reqs[abi];
|
|
|
|
|
|
|
|
|
|
if (desc->fre)
|
|
|
|
|
return FP_FRE;
|
|
|
|
|
else if (desc->fr1)
|
|
|
|
|
return FP_FR1;
|
|
|
|
|
|
|
|
|
|
return FP_FR0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Determine whether or not the CPU is capable of operating in FR0
|
|
|
|
|
floating point mode. */
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
cpu_supports_fr0_p (void)
|
|
|
|
|
{
|
|
|
|
|
#if defined __mips_isa_rev && __mips_isa_rev >= 6
|
|
|
|
|
return true;
|
|
|
|
|
#else /* !defined __mips_isa_rev | mips_isa_rev < 6 */
|
|
|
|
|
return false;
|
|
|
|
|
#endif /* defined __mips_isa_rev && mips_isa_rev >= 6 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Determine the FPU mode for the executable whose ELF header is
|
|
|
|
|
HEADER. If INTERPRETER is non-NULL, also take an interpreter whose
|
|
|
|
|
header is INTERPRETER into account.
|
|
|
|
|
|
|
|
|
|
ABIFLAGS should be HEADER's corresponding PT_MIPS_ABIFLAGS program
|
|
|
|
|
header, and ABIFLAGS1 should be that of INTERPRETER, if set. Both
|
|
|
|
|
fields may be NULL if no PT_MIPS_ABIFLAGS header is present; in
|
|
|
|
|
that case, use HEADER->e_flags to determine the ABI instead.
|
|
|
|
|
|
|
|
|
|
Return the FPU mode in *MODE. Value is 0 upon success, 1
|
|
|
|
|
otherwise, with errno set. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
determine_fpu_mode (elf_header *header, elf_header *interpreter,
|
|
|
|
|
int *mode, struct mips_elf_abi_flags *abiflags,
|
|
|
|
|
struct mips_elf_abi_flags *abiflags1)
|
|
|
|
|
{
|
|
|
|
|
int exec_abi, interpreter_abi;
|
|
|
|
|
struct mode_description *exec_desc, *interpreter_desc, common;
|
|
|
|
|
|
|
|
|
|
/* Figure out the executable's floating point ABI. First, consult
|
|
|
|
|
header->e_flags, and use the old 64-bit floating point ABI if it
|
|
|
|
|
is specified. */
|
|
|
|
|
|
|
|
|
|
exec_abi = MIPS_ABI_FP_ANY;
|
|
|
|
|
|
|
|
|
|
/* First, check HEADER->e_flags. */
|
|
|
|
|
|
|
|
|
|
if (header->e_flags & EF_MIPS_FP64)
|
|
|
|
|
exec_abi = MIPS_ABI_FP_OLD_64;
|
|
|
|
|
|
|
|
|
|
/* Next, use ABIFLAGS if it exists. */
|
|
|
|
|
|
|
|
|
|
if (abiflags && valid_abi_p (abiflags->fp_abi))
|
|
|
|
|
exec_abi = abiflags->fp_abi;
|
|
|
|
|
else if (abiflags)
|
|
|
|
|
{
|
|
|
|
|
errno = ENOEXEC;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now determine that of the interpreter. */
|
|
|
|
|
|
|
|
|
|
interpreter_abi = MIPS_ABI_FP_ANY;
|
|
|
|
|
|
|
|
|
|
if (interpreter)
|
|
|
|
|
{
|
|
|
|
|
if (interpreter->e_flags & EF_MIPS_FP64)
|
|
|
|
|
interpreter_abi = MIPS_ABI_FP_OLD_64;
|
|
|
|
|
|
|
|
|
|
if (abiflags1 && valid_abi_p (abiflags->fp_abi))
|
|
|
|
|
interpreter_abi = abiflags->fp_abi;
|
|
|
|
|
else if (abiflags1)
|
|
|
|
|
{
|
|
|
|
|
errno = ELIBBAD;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If no interpreter flag is set, just return that of the
|
|
|
|
|
executable. */
|
|
|
|
|
|
|
|
|
|
if (!interpreter)
|
|
|
|
|
{
|
|
|
|
|
*mode = fp_mode_for_abi (exec_abi);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Otherwise, compare both ABIs and try to find one which will run
|
|
|
|
|
both kinds of code.
|
|
|
|
|
|
|
|
|
|
First, see if there's an easy way out: both ABIs are identical,
|
|
|
|
|
or one ABI is MIPS_ABI_FP_ANY. */
|
|
|
|
|
|
|
|
|
|
if (exec_abi == interpreter_abi)
|
|
|
|
|
{
|
|
|
|
|
*mode = fp_mode_for_abi (exec_abi);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else if (exec_abi == MIPS_ABI_FP_ANY)
|
|
|
|
|
{
|
|
|
|
|
*mode = fp_mode_for_abi (interpreter_abi);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else if (interpreter_abi == MIPS_ABI_FP_ANY)
|
|
|
|
|
{
|
|
|
|
|
*mode = fp_mode_for_abi (exec_abi);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If that doesn't work, compare various characteristics of both
|
|
|
|
|
ABIs and select an appropriate floating point mode. */
|
|
|
|
|
|
|
|
|
|
exec_desc = &fpu_reqs[exec_abi];
|
|
|
|
|
interpreter_desc = &fpu_reqs[interpreter_abi];
|
|
|
|
|
|
|
|
|
|
/* Merge both sets of requirements. */
|
|
|
|
|
common.single = exec_desc->single && interpreter_desc->single;
|
|
|
|
|
common.soft = exec_desc->soft && interpreter_desc->soft;
|
|
|
|
|
common.fr1 = exec_desc->fr1 && interpreter_desc->fr1;
|
|
|
|
|
common.frdefault = exec_desc->frdefault && interpreter_desc->frdefault;
|
|
|
|
|
common.fre = exec_desc->fre && interpreter_desc->fre;
|
|
|
|
|
|
|
|
|
|
/* Default to a mode capable of running code expecting 32-bit
|
|
|
|
|
registers. */
|
|
|
|
|
|
|
|
|
|
if (!(header->e_flags & EF_MIPS_ABI2))
|
|
|
|
|
*mode = FP_FR0;
|
|
|
|
|
else
|
|
|
|
|
/* But in this case, use FR1. */
|
|
|
|
|
*mode = FP_FR1;
|
|
|
|
|
|
|
|
|
|
if (common.fre && !common.frdefault && !common.fr1)
|
|
|
|
|
/* Floating point emulation mode is required. */
|
|
|
|
|
*mode = FP_FRE;
|
|
|
|
|
else if ((common.fr1 && common.frdefault)
|
|
|
|
|
|| (common.single && !common.frdefault)
|
|
|
|
|
|| common.fr1)
|
|
|
|
|
/* 64-bit mode is required. */
|
|
|
|
|
*mode = FP_FR1;
|
|
|
|
|
else if (!common.fre && !common.frdefault
|
|
|
|
|
&& !common.fr1 && !common.single
|
|
|
|
|
&& !common.soft)
|
|
|
|
|
{
|
|
|
|
|
/* The floating point modes specified are incompatible. */
|
|
|
|
|
errno = ELIBBAD;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|