Hi Ying, On Thu, 2023-11-02 at 14:55 +0800, Ying Huang wrote: > In mips64 little-endian, r_info consists of four byte fields(contains > three reloc types) and a 32-bit symbol index. In order to adapt > GELF_R_SYM and GELF_R_TYPE, need convert raw data to get correct symbol > index and type.
This part and the new backends hooks look OK. > libelf/elf_getdata.c: Some eu-utils use read-mmap method to map file, > so we need to malloc and memcpy raw data to avoid segment fault. After > modification, the correct value are saved in the malloced memory not in > process address space. > libelf/elf_updata.c: Because we converted the relocation info in mips > order when we call elf_getdata.c, so we need to convert the modified data > in original order bits before writing the data to the file. But I still have some trouble fully understanding this part. I understand why you need it, as explained here: https://patchwork.sourceware.org/project/elfutils/patch/20230411081141.1762395-2-ying.hu...@oss.cipunited.com/#145284 But I still don't know if this is the right way to deal with it. Given the elf_update part is generic I rather not apply it just before doing a release (today). We could apply the other parts/patches which generally look OK. But I think it is better to do it after 0.190 is released (then people who need a mips64 backend have this patchset to apply as a whole). We'll make it a priority to get this in asap for 0.191 and try to make sure it won't be too long (max 3 months) till the next release. Cheers, Mark > --- > backends/Makefile.am | 6 +- > backends/mips_init.c | 52 ++++++++++++++++ > backends/mips_reloc.def | 93 ++++++++++++++++++++++++++++ > backends/mips_symbol.c | 63 +++++++++++++++++++ > libebl/eblopenbackend.c | 2 + > libelf/elf_getdata.c | 132 +++++++++++++++++++++++++++++++++++++++- > libelf/elf_update.c | 53 ++++++++++++++++ > libelf/libelfP.h | 3 + > 8 files changed, 400 insertions(+), 4 deletions(-) > create mode 100644 backends/mips_init.c > create mode 100644 backends/mips_reloc.def > create mode 100644 backends/mips_symbol.c > > diff --git a/backends/Makefile.am b/backends/Makefile.am > index bbb2aac7..b946fd30 100644 > --- a/backends/Makefile.am > +++ b/backends/Makefile.am > @@ -37,7 +37,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/libebl > -I$(top_srcdir)/libasm \ > noinst_LIBRARIES = libebl_backends.a libebl_backends_pic.a > > modules = i386 sh x86_64 ia64 alpha arm aarch64 sparc ppc ppc64 s390 \ > - m68k bpf riscv csky loongarch arc > + m68k bpf riscv csky loongarch arc mips > > i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c i386_cfi.c \ > i386_retval.c i386_regs.c i386_auxv.c \ > @@ -102,12 +102,14 @@ loongarch_SRCS = loongarch_init.c loongarch_symbol.c > loongarch_cfi.c \ > > arc_SRCS = arc_init.c arc_symbol.c > > +mips_SRCS = mips_init.c mips_symbol.c > + > libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \ > $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \ > $(aarch64_SRCS) $(sparc_SRCS) $(ppc_SRCS) \ > $(ppc64_SRCS) $(s390_SRCS) \ > $(m68k_SRCS) $(bpf_SRCS) $(riscv_SRCS) $(csky_SRCS) > \ > - $(loongarch_SRCS) $(arc_SRCS) > + $(loongarch_SRCS) $(arc_SRCS) $(mips_SRCS) > > libebl_backends_pic_a_SOURCES = > am_libebl_backends_pic_a_OBJECTS = $(libebl_backends_a_SOURCES:.c=.os) > diff --git a/backends/mips_init.c b/backends/mips_init.c > new file mode 100644 > index 00000000..e26da609 > --- /dev/null > +++ b/backends/mips_init.c > @@ -0,0 +1,52 @@ > +/* Initialization of MIPS specific backend library. > + Copyright (C) 2023 CIP United Inc. > + This file is part of elfutils. > + > + This file is free software; you can redistribute it and/or modify > + it under the terms of either > + > + * the GNU Lesser General Public License as published by the Free > + Software Foundation; either version 3 of the License, or (at > + your option) any later version > + > + or > + > + * the GNU General Public License as published by the Free > + Software Foundation; either version 2 of the License, or (at > + your option) any later version > + > + or both in parallel, as here. > + > + elfutils 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 copies of the GNU General Public License and > + the GNU Lesser General Public License along with this program. If > + not, see <http://www.gnu.org/licenses/>. */ > + > +#ifdef HAVE_CONFIG_H > +# include <config.h> > +#endif > + > +#define BACKEND mips_ > +#define RELOC_PREFIX R_MIPS_ > +#include "libebl_CPU.h" > +#include "libelfP.h" > + > +#define RELOC_TYPE_ID(type) ((type) & 0xff) > + > +/* This defines the common reloc hooks based on mips_reloc.def. */ > +#include "common-reloc.c" > + > +Ebl * > +mips_init (Elf *elf __attribute__ ((unused)), > + GElf_Half machine __attribute__ ((unused)), > + Ebl *eh) > +{ > + /* We handle it. */ > + mips_init_reloc (eh); > + HOOK (eh, reloc_simple_type); > + return eh; > +} > diff --git a/backends/mips_reloc.def b/backends/mips_reloc.def > new file mode 100644 > index 00000000..8cb66a54 > --- /dev/null > +++ b/backends/mips_reloc.def > @@ -0,0 +1,93 @@ > +/* List the relocation types for MIPS. -*- C -*- > + Copyright (C) 2023 CIP United Inc. > + This file is part of elfutils. > + > + This file is free software; you can redistribute it and/or modify > + it under the terms of either > + > + * the GNU Lesser General Public License as published by the Free > + Software Foundation; either version 3 of the License, or (at > + your option) any later version > + > + or > + > + * the GNU General Public License as published by the Free > + Software Foundation; either version 2 of the License, or (at > + your option) any later version > + > + or both in parallel, as here. > + > + elfutils 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 copies of the GNU General Public License and > + the GNU Lesser General Public License along with this program. If > + not, see <http://www.gnu.org/licenses/>. */ > + > +/* NAME, REL|EXEC|DYN */ > + > + > +RELOC_TYPE (NONE, REL|EXEC|DYN) > +RELOC_TYPE (16, REL|EXEC|DYN) > +RELOC_TYPE (32, REL) > +RELOC_TYPE (REL32, REL|EXEC|DYN) > +RELOC_TYPE (26, REL|DYN) > +RELOC_TYPE (HI16, REL) > +RELOC_TYPE (LO16, REL|EXEC|DYN) > +RELOC_TYPE (GPREL16, REL|EXEC|DYN) > +RELOC_TYPE (LITERAL, REL|EXEC|DYN) > +RELOC_TYPE (GOT16, REL|EXEC|DYN) > +RELOC_TYPE (PC16, REL) > +RELOC_TYPE (CALL16, REL) > +RELOC_TYPE (GPREL32, REL) > +RELOC_TYPE (SHIFT5, REL) > +RELOC_TYPE (SHIFT6, REL) > +RELOC_TYPE (64, REL) > +RELOC_TYPE (GOT_DISP, REL) > +RELOC_TYPE (GOT_PAGE, REL) > +RELOC_TYPE (GOT_OFST, REL) > +RELOC_TYPE (GOT_HI16, REL) > +RELOC_TYPE (GOT_LO16, REL) > +RELOC_TYPE (SUB, REL) > +RELOC_TYPE (INSERT_A, REL) > +RELOC_TYPE (INSERT_B, REL) > +RELOC_TYPE (DELETE, REL) > +RELOC_TYPE (HIGHER, REL) > +RELOC_TYPE (HIGHEST, REL) > +RELOC_TYPE (CALL_HI16, REL) > +RELOC_TYPE (CALL_LO16, REL) > +RELOC_TYPE (SCN_DISP, REL) > +RELOC_TYPE (REL16, REL) > +RELOC_TYPE (ADD_IMMEDIATE, REL) > +RELOC_TYPE (PJUMP, REL) > +RELOC_TYPE (RELGOT, REL) > +RELOC_TYPE (JALR, REL) > +RELOC_TYPE (TLS_DTPMOD32, DYN) > +RELOC_TYPE (TLS_DTPREL32, REL) > +RELOC_TYPE (TLS_DTPMOD64, DYN) > +RELOC_TYPE (TLS_DTPREL64, REL) > +RELOC_TYPE (TLS_GD, REL) > +RELOC_TYPE (TLS_LDM, REL) > +RELOC_TYPE (TLS_DTPREL_HI16, REL) > +RELOC_TYPE (TLS_DTPREL_LO16, REL) > +RELOC_TYPE (TLS_GOTTPREL, REL) > +RELOC_TYPE (TLS_TPREL32, REL) > +RELOC_TYPE (TLS_TPREL64, REL) > +RELOC_TYPE (TLS_TPREL_HI16, REL) > +RELOC_TYPE (TLS_TPREL_LO16, REL) > +RELOC_TYPE (GLOB_DAT, REL) > +RELOC_TYPE (PC21_S2, REL) > +RELOC_TYPE (PC26_S2, REL) > +RELOC_TYPE (PC18_S3, REL) > +RELOC_TYPE (PC19_S2, REL) > +RELOC_TYPE (PCHI16, REL) > +RELOC_TYPE (PCLO16, REL) > +RELOC_TYPE (COPY, REL) > +RELOC_TYPE (JUMP_SLOT, REL) > +RELOC_TYPE (PC32, REL) > +RELOC_TYPE (EH, REL) > +RELOC_TYPE (GNU_REL16_S2, REL) > +RELOC_TYPE (GNU_VTINHERIT, REL) > +RELOC_TYPE (GNU_VTENTRY, REL) > diff --git a/backends/mips_symbol.c b/backends/mips_symbol.c > new file mode 100644 > index 00000000..a9dd5c09 > --- /dev/null > +++ b/backends/mips_symbol.c > @@ -0,0 +1,63 @@ > +/* MIPS specific symbolic name handling. > + Copyright (C) 2023 CIP United Inc. > + This file is part of elfutils. > + > + This file is free software; you can redistribute it and/or modify > + it under the terms of either > + > + * the GNU Lesser General Public License as published by the Free > + Software Foundation; either version 3 of the License, or (at > + your option) any later version > + > + or > + > + * the GNU General Public License as published by the Free > + Software Foundation; either version 2 of the License, or (at > + your option) any later version > + > + or both in parallel, as here. > + > + elfutils 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 copies of the GNU General Public License and > + the GNU Lesser General Public License along with this program. If > + not, see <http://www.gnu.org/licenses/>. */ > + > +#ifdef HAVE_CONFIG_H > +# include <config.h> > +#endif > + > +#include <system.h> > + > +#include <elf.h> > +#include <stddef.h> > +#include <string.h> > +#include <stdio.h> > +#define BACKEND mips_ > +#include "libebl_CPU.h" > +#include "libelfP.h" > + > +/* Check for the simple reloc types. */ > +Elf_Type > +mips_reloc_simple_type (Ebl *ebl, int type, > + int *addsub __attribute__ ((unused))) > +{ > + int typeNew = type; > + if(ebl->elf->class == ELFCLASS64) > + typeNew = ELF64_MIPS_R_TYPE1(type); > + switch (typeNew) > + { > + case R_MIPS_64: > + return ELF_T_XWORD; > + case R_MIPS_32: > + return ELF_T_WORD; > + case R_MIPS_16: > + return ELF_T_HALF; > + > + default: > + return ELF_T_NUM; > + } > +} > diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c > index 084a1544..a5f7467a 100644 > --- a/libebl/eblopenbackend.c > +++ b/libebl/eblopenbackend.c > @@ -57,6 +57,7 @@ Ebl *riscv_init (Elf *, GElf_Half, Ebl *); > Ebl *csky_init (Elf *, GElf_Half, Ebl *); > Ebl *loongarch_init (Elf *, GElf_Half, Ebl *); > Ebl *arc_init (Elf *, GElf_Half, Ebl *); > +Ebl *mips_init (Elf *, GElf_Half, Ebl *); > > /* This table should contain the complete list of architectures as far > as the ELF specification is concerned. */ > @@ -154,6 +155,7 @@ static const struct > { csky_init, "elf_csky", "csky", 4, EM_CSKY, ELFCLASS32, ELFDATA2LSB }, > { loongarch_init, "elf_loongarch", "loongarch", 9, EM_LOONGARCH, > ELFCLASS64, ELFDATA2LSB }, > { arc_init, "elf_arc", "arc", 3, EM_ARCV2, ELFCLASS32, ELFDATA2LSB }, > + { mips_init, "elf_mips", "mips", 4, EM_MIPS, 0, 0 }, > }; > #define nmachines (sizeof (machines) / sizeof (machines[0])) > > diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c > index 7c3ac043..942ba536 100644 > --- a/libelf/elf_getdata.c > +++ b/libelf/elf_getdata.c > @@ -133,6 +133,119 @@ __libelf_data_type (GElf_Ehdr *ehdr, int sh_type, > GElf_Xword align) > } > } > > +/* Convert the data in the current section. */ > +static void > +convert_data_for_mips64el (Elf_Scn *scn, int eclass, > + int data, size_t size, Elf_Type type) > +{ > + /* Do we need to convert the data and/or adjust for alignment? */ > + if (data == MY_ELFDATA || type == ELF_T_BYTE) > + { > + /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need > to convert > + relocation info(raw data). Some eu-utils use read-mmap method to map > file, so > + we need to malloc and memcpy raw data to avoid segment fault. After > modification, > + the correct value are saved in the malloced memory not in process > address space. */ > + scn->data_base = malloc (size); > + if (scn->data_base == NULL) > + { > + __libelf_seterrno (ELF_E_NOMEM); > + return; > + } > + > + /* The copy will be appropriately aligned for direct access. */ > + memcpy (scn->data_base, scn->rawdata_base, size); > + } > + else > + { > + xfct_t fp; > + > + scn->data_base = malloc (size); > + if (scn->data_base == NULL) > + { > + __libelf_seterrno (ELF_E_NOMEM); > + return; > + } > + > + /* Make sure the source is correctly aligned for the conversion > + function to directly access the data elements. */ > + char *rawdata_source; > + /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need > to convert > + relocation info(raw data). Some eu-utils use read-mmap method to map > file, so > + we need to malloc and memcpy raw data to avoid segment fault. After > modification, > + the correct value are saved in the malloced memory not in process > address space. */ > + rawdata_source = malloc (size); > + if (rawdata_source == NULL) > + { > + __libelf_seterrno (ELF_E_NOMEM); > + return; > + } > + > + /* The copy will be appropriately aligned for direct access. */ > + memcpy (rawdata_source, scn->rawdata_base, size); > + > + /* Get the conversion function. */ > + fp = __elf_xfctstom[eclass - 1][type]; > + > + fp (scn->data_base, rawdata_source, size, 0); > + > + if (rawdata_source != scn->rawdata_base) > + free (rawdata_source); > + } > + > + scn->data_list.data.d.d_buf = scn->data_base; > + scn->data_list.data.d.d_size = size; > + scn->data_list.data.d.d_type = type; > + scn->data_list.data.d.d_off = scn->rawdata.d.d_off; > + scn->data_list.data.d.d_align = scn->rawdata.d.d_align; > + scn->data_list.data.d.d_version = scn->rawdata.d.d_version; > + > + scn->data_list.data.s = scn; > + > + /* In mips64 little-endian, r_info consists of four byte fields(contains > + three reloc types) and a 32-bit symbol index. In order to adapt > + GELF_R_SYM and GELF_R_TYPE, need to convert r_info to get correct symbol > + index and type. */ > + /* references: > + https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf > + Page40 && Page41 */ > + GElf_Shdr shdr_mem; > + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); > + if (shdr->sh_type == SHT_REL) > + { > + size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, EV_CURRENT); > + int nentries = shdr->sh_size / sh_entsize; > + for (int cnt = 0; cnt < nentries; ++cnt) > + { > + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d; > + Elf64_Rel *value = &((Elf64_Rel *) data_scn->d.d_buf)[cnt]; > + Elf64_Xword info = value->r_info; > + value->r_info = (((info & 0xffffffff) << 32) > + | ((info >> 56) & 0xff) > + | ((info >> 40) & 0xff00) > + | ((info >> 24) & 0xff0000) > + | ((info >> 8) & 0xff000000)); > + ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value; > + } > + } > + else if (shdr->sh_type == SHT_RELA) > + { > + size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, EV_CURRENT); > + int nentries = shdr->sh_size / sh_entsize; > + for (int cnt = 0; cnt < nentries; cnt++) > + { > + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d; > + Elf64_Rela *value = &((Elf64_Rela *) data_scn->d.d_buf)[cnt]; > + Elf64_Xword info = value->r_info; > + value->r_info = (((info & 0xffffffff) << 32) > + | ((info >> 56) & 0xff) > + | ((info >> 40) & 0xff00) > + | ((info >> 24) & 0xff0000) > + | ((info >> 8) & 0xff000000)); > + ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value; > + } > + } > +} > + > /* Convert the data in the current section. */ > static void > convert_data (Elf_Scn *scn, int eclass, > @@ -451,8 +564,23 @@ __libelf_set_data_list_rdlock (Elf_Scn *scn, int > wrlocked) > return; > } > > - /* Convert according to the version and the type. */ > - convert_data (scn, elf->class, > + GElf_Shdr shdr_mem; > + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); > + GElf_Ehdr ehdr_mem; > + GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem); > + if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type == > SHT_REL) && > + scn->elf->class == ELFCLASS64 && ehdr != NULL && > + ehdr->e_machine == EM_MIPS && ehdr->e_ident[EI_DATA] == ELFDATA2LSB) > + convert_data_for_mips64el (scn, elf->class, > + (elf->class == ELFCLASS32 > + || (offsetof (struct Elf, state.elf32.ehdr) > + == offsetof (struct Elf, state.elf64.ehdr)) > + ? elf->state.elf32.ehdr->e_ident[EI_DATA] > + : elf->state.elf64.ehdr->e_ident[EI_DATA]), > + scn->rawdata.d.d_size, scn->rawdata.d.d_type); > + else > + /* Convert according to the version and the type. */ > + convert_data (scn, elf->class, > (elf->class == ELFCLASS32 > || (offsetof (struct Elf, state.elf32.ehdr) > == offsetof (struct Elf, state.elf64.ehdr)) > diff --git a/libelf/elf_update.c b/libelf/elf_update.c > index 56af3a1c..aec19b7c 100644 > --- a/libelf/elf_update.c > +++ b/libelf/elf_update.c > @@ -228,7 +228,60 @@ elf_update (Elf *elf, Elf_Cmd cmd) > size = -1; > } > else > + { > + /* Because we converted the relocation info in mips order when we > call elf_getdata.c, > + so we need to convert the modified data in original order bits > before writing the > + data to the file. */ > + Elf_Scn *scn = NULL; > + while ((scn = elf_nextscn (elf, scn)) != NULL) > + { > + GElf_Shdr shdr_mem; > + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); > + GElf_Ehdr ehdr_mem; > + GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem); > + if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type > == SHT_REL) && > + scn->elf->class == ELFCLASS64 && > + ehdr != NULL && ehdr->e_machine == EM_MIPS && > ehdr->e_ident[EI_DATA] == ELFDATA2LSB) > + { > + Elf_Data *d = elf_getdata (scn, NULL); > + if (shdr->sh_type == SHT_REL) > + { > + size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, > EV_CURRENT); > + int nentries = shdr->sh_size / sh_entsize; > + for (int cnt = 0; cnt < nentries; ++cnt) > + { > + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d; > + Elf64_Rel *value = &((Elf64_Rel *) > data_scn->d.d_buf)[cnt]; > + Elf64_Xword info = value->r_info; > + value->r_info = (info >> 32 > + | ((info << 56) & 0xff00000000000000) > + | ((info << 40) & 0xff000000000000) > + | ((info << 24) & 0xff0000000000) > + | ((info << 8) & 0xff00000000)); > + ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value; > + } > + } > + else if (shdr->sh_type == SHT_RELA) > + { > + size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, > EV_CURRENT); > + int nentries = shdr->sh_size / sh_entsize; > + for (int cnt = 0; cnt < nentries; cnt++) > + { > + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d; > + Elf64_Rela *value = &((Elf64_Rela *) > data_scn->d.d_buf)[cnt]; > + Elf64_Xword info = value->r_info; > + value->r_info = (info >> 32 > + | ((info << 56) & 0xff00000000000000) > + | ((info << 40) & 0xff000000000000) > + | ((info << 24) & 0xff0000000000) > + | ((info << 8) & 0xff00000000)); > + ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value; > + } > + } > + } > + } > size = write_file (elf, size, change_bo, shnum); > + } > } > > out: > diff --git a/libelf/libelfP.h b/libelf/libelfP.h > index ed061abb..bdd2cc6a 100644 > --- a/libelf/libelfP.h > +++ b/libelf/libelfP.h > @@ -617,4 +617,7 @@ extern void __libelf_reset_rawdata (Elf_Scn *scn, void > *buf, size_t size, > #define INVALID_NDX(ndx, type, data) \ > unlikely ((data)->d_size / sizeof (type) <= (unsigned int) (ndx)) > > +#define ELF64_MIPS_R_TYPE1(i) ((i) & 0xff) > +#define ELF64_MIPS_R_TYPE2(i) (((i) >> 8) & 0xff) > +#define ELF64_MIPS_R_TYPE3(i) (((i) >> 16) & 0xff) > #endif /* libelfP.h */