Skip to content

Commit 150e3c9

Browse files
Merge patch series "riscv: support ELF format binaries in nommu mode"
Greg Ungerer <gerg@kernel.org> says: The following changes add the ability to run ELF format binaries when running RISC-V in nommu mode. That support is actually part of the ELF-FDPIC loader, so these changes are all about making that work on RISC-V. The first issue to deal with is making the ELF-FDPIC loader capable of handling 64-bit ELF files. As coded right now it only supports 32-bit ELF files. Secondly some changes are required to enable and compile the ELF-FDPIC loader on RISC-V and to pass the ELF-FDPIC mapping addresses through to user space when execing the new program. These changes have not been used to run actual ELF-FDPIC binaries. It is used to load and run normal ELF - compiled -pie format. Though the underlying changes are expected to work with full ELF-FDPIC binaries if or when that is supported on RISC-V in gcc. To avoid needing changes to the C-library (tested with uClibc-ng currently) there is a simple runtime dynamic loader (interpreter) available to do the final relocations, https://github.com/gregungerer/uldso. The nice thing about doing it this way is that the same program binary can also be loaded with the usual ELF loader in MMU linux. The motivation here is to provide an easy to use alternative to the flat format binaries normally used for RISC-V nommu based systems. * b4-shazam-merge: riscv: support the elf-fdpic binfmt loader binfmt_elf_fdpic: support 64-bit systems Link: https://lore.kernel.org/r/20230711130754.481209-1-gerg@kernel.org Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
2 parents 7f7d3ea + 9549fb3 commit 150e3c9

File tree

7 files changed

+67
-22
lines changed

7 files changed

+67
-22
lines changed

arch/riscv/include/asm/elf.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ extern bool compat_elf_check_arch(Elf32_Ehdr *hdr);
4141
#define compat_elf_check_arch compat_elf_check_arch
4242

4343
#define CORE_DUMP_USE_REGSET
44+
#define ELF_FDPIC_CORE_EFLAGS 0
4445
#define ELF_EXEC_PAGESIZE (PAGE_SIZE)
4546

4647
/*
@@ -69,6 +70,13 @@ extern bool compat_elf_check_arch(Elf32_Ehdr *hdr);
6970
#define ELF_HWCAP riscv_get_elf_hwcap()
7071
extern unsigned long elf_hwcap;
7172

73+
#define ELF_FDPIC_PLAT_INIT(_r, _exec_map_addr, _interp_map_addr, dynamic_addr) \
74+
do { \
75+
(_r)->a1 = _exec_map_addr; \
76+
(_r)->a2 = _interp_map_addr; \
77+
(_r)->a3 = dynamic_addr; \
78+
} while (0)
79+
7280
/*
7381
* This yields a string that ld.so will use to load implementation
7482
* specific libraries for optimization. This is more specific in
@@ -78,7 +86,6 @@ extern unsigned long elf_hwcap;
7886

7987
#define COMPAT_ELF_PLATFORM (NULL)
8088

81-
#ifdef CONFIG_MMU
8289
#define ARCH_DLINFO \
8390
do { \
8491
/* \
@@ -115,6 +122,8 @@ do { \
115122
else \
116123
NEW_AUX_ENT(AT_IGNORE, 0); \
117124
} while (0)
125+
126+
#ifdef CONFIG_MMU
118127
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
119128
struct linux_binprm;
120129
extern int arch_setup_additional_pages(struct linux_binprm *bprm,

arch/riscv/include/asm/mmu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ typedef struct {
2020
/* A local icache flush is needed before user execution can resume. */
2121
cpumask_t icache_stale_mask;
2222
#endif
23+
#ifdef CONFIG_BINFMT_ELF_FDPIC
24+
unsigned long exec_fdpic_loadmap;
25+
unsigned long interp_fdpic_loadmap;
26+
#endif
2327
} mm_context_t;
2428

2529
void __init create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa,

arch/riscv/include/uapi/asm/ptrace.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010

1111
#include <linux/types.h>
1212

13+
#define PTRACE_GETFDPIC 33
14+
15+
#define PTRACE_GETFDPIC_EXEC 0
16+
#define PTRACE_GETFDPIC_INTERP 1
17+
1318
/*
1419
* User-mode register state for core dumps, ptrace, sigcontext
1520
*

fs/Kconfig.binfmt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ config ARCH_USE_GNU_PROPERTY
5858
config BINFMT_ELF_FDPIC
5959
bool "Kernel support for FDPIC ELF binaries"
6060
default y if !BINFMT_ELF
61-
depends on ARM || ((M68K || SUPERH || XTENSA) && !MMU)
61+
depends on ARM || ((M68K || RISCV || SUPERH || XTENSA) && !MMU)
6262
select ELFCORE
6363
help
6464
ELF FDPIC binaries are based on ELF, but allow the individual load

fs/binfmt_elf_fdpic.c

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ static int is_constdisp(struct elfhdr *hdr)
138138
static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *params,
139139
struct file *file)
140140
{
141-
struct elf32_phdr *phdr;
141+
struct elf_phdr *phdr;
142142
unsigned long size;
143143
int retval, loop;
144144
loff_t pos = params->hdr.e_phoff;
@@ -560,8 +560,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
560560
sp &= ~7UL;
561561

562562
/* stack the load map(s) */
563-
len = sizeof(struct elf32_fdpic_loadmap);
564-
len += sizeof(struct elf32_fdpic_loadseg) * exec_params->loadmap->nsegs;
563+
len = sizeof(struct elf_fdpic_loadmap);
564+
len += sizeof(struct elf_fdpic_loadseg) * exec_params->loadmap->nsegs;
565565
sp = (sp - len) & ~7UL;
566566
exec_params->map_addr = sp;
567567

@@ -571,8 +571,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
571571
current->mm->context.exec_fdpic_loadmap = (unsigned long) sp;
572572

573573
if (interp_params->loadmap) {
574-
len = sizeof(struct elf32_fdpic_loadmap);
575-
len += sizeof(struct elf32_fdpic_loadseg) *
574+
len = sizeof(struct elf_fdpic_loadmap);
575+
len += sizeof(struct elf_fdpic_loadseg) *
576576
interp_params->loadmap->nsegs;
577577
sp = (sp - len) & ~7UL;
578578
interp_params->map_addr = sp;
@@ -740,13 +740,13 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
740740
struct mm_struct *mm,
741741
const char *what)
742742
{
743-
struct elf32_fdpic_loadmap *loadmap;
743+
struct elf_fdpic_loadmap *loadmap;
744744
#ifdef CONFIG_MMU
745-
struct elf32_fdpic_loadseg *mseg;
745+
struct elf_fdpic_loadseg *mseg;
746746
unsigned long load_addr;
747747
#endif
748-
struct elf32_fdpic_loadseg *seg;
749-
struct elf32_phdr *phdr;
748+
struct elf_fdpic_loadseg *seg;
749+
struct elf_phdr *phdr;
750750
unsigned nloads, tmp;
751751
unsigned long stop;
752752
int loop, ret;
@@ -766,7 +766,7 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
766766

767767
params->loadmap = loadmap;
768768

769-
loadmap->version = ELF32_FDPIC_LOADMAP_VERSION;
769+
loadmap->version = ELF_FDPIC_LOADMAP_VERSION;
770770
loadmap->nsegs = nloads;
771771

772772
/* map the requested LOADs into the memory space */
@@ -839,8 +839,8 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
839839
if (phdr->p_vaddr >= seg->p_vaddr &&
840840
phdr->p_vaddr + phdr->p_memsz <=
841841
seg->p_vaddr + seg->p_memsz) {
842-
Elf32_Dyn __user *dyn;
843-
Elf32_Sword d_tag;
842+
Elf_Dyn __user *dyn;
843+
Elf_Sword d_tag;
844844

845845
params->dynamic_addr =
846846
(phdr->p_vaddr - seg->p_vaddr) +
@@ -850,11 +850,11 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
850850
* one item, and that the last item is a NULL
851851
* entry */
852852
if (phdr->p_memsz == 0 ||
853-
phdr->p_memsz % sizeof(Elf32_Dyn) != 0)
853+
phdr->p_memsz % sizeof(Elf_Dyn) != 0)
854854
goto dynamic_error;
855855

856-
tmp = phdr->p_memsz / sizeof(Elf32_Dyn);
857-
dyn = (Elf32_Dyn __user *)params->dynamic_addr;
856+
tmp = phdr->p_memsz / sizeof(Elf_Dyn);
857+
dyn = (Elf_Dyn __user *)params->dynamic_addr;
858858
if (get_user(d_tag, &dyn[tmp - 1].d_tag) ||
859859
d_tag != 0)
860860
goto dynamic_error;
@@ -923,8 +923,8 @@ static int elf_fdpic_map_file_constdisp_on_uclinux(
923923
struct file *file,
924924
struct mm_struct *mm)
925925
{
926-
struct elf32_fdpic_loadseg *seg;
927-
struct elf32_phdr *phdr;
926+
struct elf_fdpic_loadseg *seg;
927+
struct elf_phdr *phdr;
928928
unsigned long load_addr, base = ULONG_MAX, top = 0, maddr = 0;
929929
int loop, ret;
930930

@@ -1007,8 +1007,8 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
10071007
struct file *file,
10081008
struct mm_struct *mm)
10091009
{
1010-
struct elf32_fdpic_loadseg *seg;
1011-
struct elf32_phdr *phdr;
1010+
struct elf_fdpic_loadseg *seg;
1011+
struct elf_phdr *phdr;
10121012
unsigned long load_addr, delta_vaddr;
10131013
int loop, dvset;
10141014

include/linux/elf-fdpic.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,25 @@
1010

1111
#include <uapi/linux/elf-fdpic.h>
1212

13+
#if ELF_CLASS == ELFCLASS32
14+
#define Elf_Sword Elf32_Sword
15+
#define elf_fdpic_loadseg elf32_fdpic_loadseg
16+
#define elf_fdpic_loadmap elf32_fdpic_loadmap
17+
#define ELF_FDPIC_LOADMAP_VERSION ELF32_FDPIC_LOADMAP_VERSION
18+
#else
19+
#define Elf_Sword Elf64_Sxword
20+
#define elf_fdpic_loadmap elf64_fdpic_loadmap
21+
#define elf_fdpic_loadseg elf64_fdpic_loadseg
22+
#define ELF_FDPIC_LOADMAP_VERSION ELF64_FDPIC_LOADMAP_VERSION
23+
#endif
24+
1325
/*
1426
* binfmt binary parameters structure
1527
*/
1628
struct elf_fdpic_params {
1729
struct elfhdr hdr; /* ref copy of ELF header */
1830
struct elf_phdr *phdrs; /* ref copy of PT_PHDR table */
19-
struct elf32_fdpic_loadmap *loadmap; /* loadmap to be passed to userspace */
31+
struct elf_fdpic_loadmap *loadmap; /* loadmap to be passed to userspace */
2032
unsigned long elfhdr_addr; /* mapped ELF header user address */
2133
unsigned long ph_addr; /* mapped PT_PHDR user address */
2234
unsigned long map_addr; /* mapped loadmap user address */

include/uapi/linux/elf-fdpic.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,19 @@ struct elf32_fdpic_loadmap {
3232

3333
#define ELF32_FDPIC_LOADMAP_VERSION 0x0000
3434

35+
/* segment mappings for ELF FDPIC libraries/executables/interpreters */
36+
struct elf64_fdpic_loadseg {
37+
Elf64_Addr addr; /* core address to which mapped */
38+
Elf64_Addr p_vaddr; /* VMA recorded in file */
39+
Elf64_Word p_memsz; /* allocation size recorded in file */
40+
};
41+
42+
struct elf64_fdpic_loadmap {
43+
Elf64_Half version; /* version of these structures, just in case... */
44+
Elf64_Half nsegs; /* number of segments */
45+
struct elf64_fdpic_loadseg segs[];
46+
};
47+
48+
#define ELF64_FDPIC_LOADMAP_VERSION 0x0000
49+
3550
#endif /* _UAPI_LINUX_ELF_FDPIC_H */

0 commit comments

Comments
 (0)