Message ID | 20211020220700.04bcdeca@xhacker (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | riscv: switch to relative extable | expand |
On 2021/10/20 22:07, Jisheng Zhang wrote: > From: Jisheng Zhang <jszhang@kernel.org> > > Similar as other architectures such as arm64, x86 and so on, use > offsets relative to the exception table entry values rather than > absolute addresses for both the exception locationand the fixup. > > However, RISCV label difference will actually produce two relocations, > a pair of R_RISCV_ADD32 and R_RISCV_SUB32. Take below simple code for > example: > > $ cat test.S > .section .text > 1: > nop > .section __ex_table,"a" > .balign 4 > .long (1b - .) > .previous > > $ riscv64-linux-gnu-gcc -c test.S > $ riscv64-linux-gnu-readelf -r test.o > Relocation section '.rela__ex_table' at offset 0x100 contains 2 entries: > Offset Info Type Sym. Value Sym. Name + Addend > 000000000000 000600000023 R_RISCV_ADD32 0000000000000000 .L1^B1 + 0 > 000000000000 000500000027 R_RISCV_SUB32 0000000000000000 .L0 + 0 > > The modpost will complain the R_RISCV_SUB32 relocation, so we need to > patch modpost.c to skip this relocation for .rela__ex_table section. > > After this patch, the __ex_table section size of defconfig vmlinux is > reduced from 7072 Bytes to 3536 Bytes. > > Signed-off-by: Jisheng Zhang <jszhang@kernel.org> > --- ... > diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c > index cb8ab7d91d30..0aa14b5bd124 100644 > --- a/scripts/mod/modpost.c > +++ b/scripts/mod/modpost.c > @@ -1830,6 +1830,27 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) > return 0; > } > > +#ifndef EM_RISCV > +#define EM_RISCV 243 > +#endif > + > +#ifndef R_RISCV_SUB32 > +#define R_RISCV_SUB32 39 > +#endif > + > +static int addend_riscv_rela(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) > +{ > + unsigned int r_typ = ELF_R_TYPE(r->r_info); > + const char *fromsec; > + > + fromsec = sech_name(elf, sechdr); > + fromsec += strlen(".rela"); > + > + if (!strcmp("__ex_table", fromsec) && r_typ == R_RISCV_SUB32) > + return 1; /* skip this */ > + return 0; > +} > + > static void section_rela(const char *modname, struct elf_info *elf, > Elf_Shdr *sechdr) > { > @@ -1866,6 +1887,12 @@ static void section_rela(const char *modname, struct elf_info *elf, > r_sym = ELF_R_SYM(r.r_info); > #endif > r.r_addend = TO_NATIVE(rela->r_addend); > + switch (elf->hdr->e_machine) { > + case EM_RISCV: > + if (addend_riscv_rela(elf, sechdr, &r)) directly use if (!strcmp("__ex_table", fromsec) && ELF_R_TYPE(r.r_info) == R_RISCV_SUB32) > + continue; > + break; > + } > sym = elf->symtab_start + r_sym; > /* Skip special sections */ > if (is_shndx_special(sym->st_shndx)) > diff --git a/scripts/sorttable.c b/scripts/sorttable.c > index 6ee4fa882919..39e86e4acea3 100644 > --- a/scripts/sorttable.c > +++ b/scripts/sorttable.c > @@ -346,6 +346,7 @@ static int do_file(char const *const fname, void *addr) > case EM_PARISC: > case EM_PPC: > case EM_PPC64: > + case EM_RISCV: > custom_sort = sort_relative_table; > break; > case EM_ARCOMPACT: > @@ -353,7 +354,6 @@ static int do_file(char const *const fname, void *addr) > case EM_ARM: > case EM_MICROBLAZE: > case EM_MIPS: > - case EM_RISCV: > case EM_XTENSA: > break; > default: >
On Thu, 21 Oct 2021 19:42:48 +0800 Kefeng Wang <wangkefeng.wang@huawei.com> wrote: > On 2021/10/20 22:07, Jisheng Zhang wrote: > > From: Jisheng Zhang <jszhang@kernel.org> > > > > Similar as other architectures such as arm64, x86 and so on, use > > offsets relative to the exception table entry values rather than > > absolute addresses for both the exception locationand the fixup. > > > > However, RISCV label difference will actually produce two relocations, > > a pair of R_RISCV_ADD32 and R_RISCV_SUB32. Take below simple code for > > example: > > > > $ cat test.S > > .section .text > > 1: > > nop > > .section __ex_table,"a" > > .balign 4 > > .long (1b - .) > > .previous > > > > $ riscv64-linux-gnu-gcc -c test.S > > $ riscv64-linux-gnu-readelf -r test.o > > Relocation section '.rela__ex_table' at offset 0x100 contains 2 entries: > > Offset Info Type Sym. Value Sym. Name + Addend > > 000000000000 000600000023 R_RISCV_ADD32 0000000000000000 .L1^B1 + 0 > > 000000000000 000500000027 R_RISCV_SUB32 0000000000000000 .L0 + 0 > > > > The modpost will complain the R_RISCV_SUB32 relocation, so we need to > > patch modpost.c to skip this relocation for .rela__ex_table section. > > > > After this patch, the __ex_table section size of defconfig vmlinux is > > reduced from 7072 Bytes to 3536 Bytes. > > > > Signed-off-by: Jisheng Zhang <jszhang@kernel.org> > > --- > > > > ... > > diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c > > index cb8ab7d91d30..0aa14b5bd124 100644 > > --- a/scripts/mod/modpost.c > > +++ b/scripts/mod/modpost.c > > @@ -1830,6 +1830,27 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) > > return 0; > > } > > > > +#ifndef EM_RISCV > > +#define EM_RISCV 243 > > +#endif > > + > > +#ifndef R_RISCV_SUB32 > > +#define R_RISCV_SUB32 39 > > +#endif > > + > > +static int addend_riscv_rela(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) > > +{ > > + unsigned int r_typ = ELF_R_TYPE(r->r_info); > > + const char *fromsec; > > + > > + fromsec = sech_name(elf, sechdr); > > + fromsec += strlen(".rela"); > > + > > + if (!strcmp("__ex_table", fromsec) && r_typ == R_RISCV_SUB32) > > + return 1; /* skip this */ > > + return 0; > > +} > > + > > static void section_rela(const char *modname, struct elf_info *elf, > > Elf_Shdr *sechdr) > > { > > @@ -1866,6 +1887,12 @@ static void section_rela(const char *modname, struct elf_info *elf, > > r_sym = ELF_R_SYM(r.r_info); > > #endif > > r.r_addend = TO_NATIVE(rela->r_addend); > > + switch (elf->hdr->e_machine) { > > + case EM_RISCV: > > + if (addend_riscv_rela(elf, sechdr, &r)) > directly use > if (!strcmp("__ex_table", fromsec) && ELF_R_TYPE(r.r_info) == R_RISCV_SUB32) My local initial patch is as direct as this LoC;) then later I thought we may need do something more in future. But now I think we can do code refactoring then. Will send patch v3 soon. Thanks > > > + continue; > > + break; > > + } > > sym = elf->symtab_start + r_sym; > > /* Skip special sections */ > > if (is_shndx_special(sym->st_shndx)) > > diff --git a/scripts/sorttable.c b/scripts/sorttable.c > > index 6ee4fa882919..39e86e4acea3 100644 > > --- a/scripts/sorttable.c > > +++ b/scripts/sorttable.c > > @@ -346,6 +346,7 @@ static int do_file(char const *const fname, void *addr) > > case EM_PARISC: > > case EM_PPC: > > case EM_PPC64: > > + case EM_RISCV: > > custom_sort = sort_relative_table; > > break; > > case EM_ARCOMPACT: > > @@ -353,7 +354,6 @@ static int do_file(char const *const fname, void *addr) > > case EM_ARM: > > case EM_MICROBLAZE: > > case EM_MIPS: > > - case EM_RISCV: > > case EM_XTENSA: > > break; > > default: > >
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild index 445ccc97305a..57b86fd9916c 100644 --- a/arch/riscv/include/asm/Kbuild +++ b/arch/riscv/include/asm/Kbuild @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 generic-y += early_ioremap.h -generic-y += extable.h generic-y += flat.h generic-y += kvm_para.h generic-y += user.h diff --git a/arch/riscv/include/asm/extable.h b/arch/riscv/include/asm/extable.h new file mode 100644 index 000000000000..bc439b0fdb29 --- /dev/null +++ b/arch/riscv/include/asm/extable.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_RISCV_EXTABLE_H +#define _ASM_RISCV_EXTABLE_H + +/* + * The exception table consists of pairs of relative offsets: the first + * is the relative offset to an instruction that is allowed to fault, + * and the second is the relative offset at which the program should + * continue. No registers are modified, so it is entirely up to the + * continuation code to figure out what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry { + int insn, fixup; +}; + +#define ARCH_HAS_RELATIVE_EXTABLE + +extern int fixup_exception(struct pt_regs *regs); +#endif diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index 35802e72ace8..540903c7d3e8 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -12,8 +12,8 @@ #define _ASM_EXTABLE(from, to) \ " .pushsection __ex_table, \"a\"\n" \ - " .balign " RISCV_SZPTR " \n" \ - " " RISCV_PTR "(" #from "), (" #to ")\n" \ + " .balign 4\n" \ + " .long (" #from " - .), (" #to " - .)\n" \ " .popsection\n" /* diff --git a/arch/riscv/lib/uaccess.S b/arch/riscv/lib/uaccess.S index 63bc691cff91..55f80f84e23f 100644 --- a/arch/riscv/lib/uaccess.S +++ b/arch/riscv/lib/uaccess.S @@ -7,8 +7,8 @@ 100: \op \reg, \addr .section __ex_table,"a" - .balign RISCV_SZPTR - RISCV_PTR 100b, \lbl + .balign 4 + .long (100b - .), (\lbl - .) .previous .endm diff --git a/arch/riscv/mm/extable.c b/arch/riscv/mm/extable.c index 2fc729422151..6aa8ffac4be7 100644 --- a/arch/riscv/mm/extable.c +++ b/arch/riscv/mm/extable.c @@ -17,7 +17,7 @@ int fixup_exception(struct pt_regs *regs) fixup = search_exception_tables(regs->epc); if (fixup) { - regs->epc = fixup->fixup; + regs->epc = (unsigned long)&fixup->fixup + fixup->fixup; return 1; } return 0; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index cb8ab7d91d30..0aa14b5bd124 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1830,6 +1830,27 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) return 0; } +#ifndef EM_RISCV +#define EM_RISCV 243 +#endif + +#ifndef R_RISCV_SUB32 +#define R_RISCV_SUB32 39 +#endif + +static int addend_riscv_rela(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) +{ + unsigned int r_typ = ELF_R_TYPE(r->r_info); + const char *fromsec; + + fromsec = sech_name(elf, sechdr); + fromsec += strlen(".rela"); + + if (!strcmp("__ex_table", fromsec) && r_typ == R_RISCV_SUB32) + return 1; /* skip this */ + return 0; +} + static void section_rela(const char *modname, struct elf_info *elf, Elf_Shdr *sechdr) { @@ -1866,6 +1887,12 @@ static void section_rela(const char *modname, struct elf_info *elf, r_sym = ELF_R_SYM(r.r_info); #endif r.r_addend = TO_NATIVE(rela->r_addend); + switch (elf->hdr->e_machine) { + case EM_RISCV: + if (addend_riscv_rela(elf, sechdr, &r)) + continue; + break; + } sym = elf->symtab_start + r_sym; /* Skip special sections */ if (is_shndx_special(sym->st_shndx)) diff --git a/scripts/sorttable.c b/scripts/sorttable.c index 6ee4fa882919..39e86e4acea3 100644 --- a/scripts/sorttable.c +++ b/scripts/sorttable.c @@ -346,6 +346,7 @@ static int do_file(char const *const fname, void *addr) case EM_PARISC: case EM_PPC: case EM_PPC64: + case EM_RISCV: custom_sort = sort_relative_table; break; case EM_ARCOMPACT: @@ -353,7 +354,6 @@ static int do_file(char const *const fname, void *addr) case EM_ARM: case EM_MICROBLAZE: case EM_MIPS: - case EM_RISCV: case EM_XTENSA: break; default: