[1/5] strip: Adapt src/strip -o -f on mips

Message ID 20230411081141.1762395-2-ying.huang@oss.cipunited.com
State Superseded
Headers
Series Add support for MIPS |

Commit Message

Ying Huang April 11, 2023, 8:12 a.m. UTC
  From: Ying Huang <ying.huang@oss.cipunited.com>

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.

  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.
---
 backends/Makefile.am    |  6 ++-
 backends/mips_init.c    | 49 +++++++++++++++++++++
 backends/mips_reloc.def | 93 +++++++++++++++++++++++++++++++++++++++
 backends/mips_symbol.c  | 62 ++++++++++++++++++++++++++
 libebl/eblopenbackend.c |  2 +
 libelf/elf.h            | 65 +++++++++++++++++++++++++++-
 libelf/elf_getdata.c    | 96 +++++++++++++++++++++++++++++++++++++++--
 libelf/elf_update.c     | 53 +++++++++++++++++++++++
 8 files changed, 419 insertions(+), 7 deletions(-)
 create mode 100644 backends/mips_init.c
 create mode 100644 backends/mips_reloc.def
 create mode 100644 backends/mips_symbol.c
  

Comments

Mark Wielaard May 9, 2023, 3:15 p.m. UTC | #1
Hi,

On Tue, 2023-04-11 at 16:12 +0800, Ying Huang wrote:
> From: Ying Huang <ying.huang@oss.cipunited.com>
> 
> 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.

Is there a spec that describes this?

I see you adjusted elf.h to include:

+#define ELF64_MIPS_R_TYPE(i)		((i) & 0xff)
+#define ELF64_MIPS_R_TYPE2(i)           (((i) >> 8) & 0xff)
+#define ELF64_MIPS_R_TYPE3(i)           (((i) >> 16) & 0xff)

And various new relocation types for MIPS variants.
Our elf.h comes from the glibc project. Have you also submitted these
changes to libc-alpha@sourceware.org ?

>   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.

Where do these segfaults show up?

>   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.

It feels like this is in the wrong place and doesn't take into account
whether the program itself is running on a big or little endian
machine.

Maybe I am misunderstanding why this conversion is needed always. But I
would have expected a specific conversion function for MIPS for
ELF_T_REL and/or ELF_T_RELA (which are currently generic).

Cheers,

Mark
  
Ying Huang May 16, 2023, 6:38 a.m. UTC | #2
Hi,

在 2023/5/9 23:15, Mark Wielaard 写道:
> Hi,
>
> On Tue, 2023-04-11 at 16:12 +0800, Ying Huang wrote:
>> From: Ying Huang <ying.huang@oss.cipunited.com>
>>
>> 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.
> Is there a spec that describes this?
   

 references:

    https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf

    Page40 && Page41

>
> I see you adjusted elf.h to include:
>
> +#define ELF64_MIPS_R_TYPE(i)		((i) & 0xff)
> +#define ELF64_MIPS_R_TYPE2(i)           (((i) >> 8) & 0xff)
> +#define ELF64_MIPS_R_TYPE3(i)           (((i) >> 16) & 0xff)
>
> And various new relocation types for MIPS variants.
> Our elf.h comes from the glibc project. Have you also submitted these
> changes to libc-alpha@sourceware.org ?
    Has submitted.

    https://sourceware.org/pipermail/libc-alpha/2023-May/148026.html

    https://sourceware.org/pipermail/libc-alpha/2023-May/148112.html

>
>>   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.
> Where do these segfaults show up?

>
>>   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.
    Has tested on big/little endian machine with big/little endian ELF file, all were OK.
> It feels like this is in the wrong place and doesn't take into account
> whether the program itself is running on a big or little endian
> machine.
>
> Maybe I am misunderstanding why this conversion is needed always. But I
> would have expected a specific conversion function for MIPS for
> ELF_T_REL and/or ELF_T_RELA (which are currently generic).
>
> Cheers,
>
> Mark
    1.Considering that some people directly use the original data instead of the interface function gelf_getrela;

    2.Because there is only one parameter, so can not modify the macro ELF64_R_TYPE;

    3.If the mips interface function is added, other packages using libelf will not be compatible with mips, and the place where gelf_getrela is used need be modified.

    Where do you think is the most suitable place to do mips conversion?

Thanks,

Ying
  
Ying Huang May 16, 2023, 6:46 a.m. UTC | #3
HI,

>>   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.
> Where do these segfaults show up?
    The screenshot of the segment error was not uploaded successfully in the last email, upload again.

Thanks,

YIng
  
Ying Huang May 16, 2023, 7:34 a.m. UTC | #4
在 2023/5/16 14:46, Ying Huang 写道:
>
> HI,
>
> >> 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.
> > Where do these segfaults show up?
>     The screenshot of the segment error was not uploaded successfully in the last email, upload again.
>
> Thanks,
>
> YIng
>

huangying@Sleepygon:~/elf/elfutils_4$ src/elflint src/nm.o
Segmentation fault
huangying@Sleepygon:~/elf/elfutils_4$ src/elflint src/strip.o
Segmentation fault
  
Luke Diamand May 16, 2023, 8:05 a.m. UTC | #5
On 09/05/2023 16:15, Mark Wielaard wrote:
> Hi,
> 
> On Tue, 2023-04-11 at 16:12 +0800, Ying Huang wrote:
>> From: Ying Huang <ying.huang@oss.cipunited.com>
>>
>> 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.
> 
> Is there a spec that describes this?
> 
> I see you adjusted elf.h to include:
> 
> +#define ELF64_MIPS_R_TYPE(i)		((i) & 0xff)
> +#define ELF64_MIPS_R_TYPE2(i)           (((i) >> 8) & 0xff)
> +#define ELF64_MIPS_R_TYPE3(i)           (((i) >> 16) & 0xff)
> 

Is this patch intended to support 32 bit MIPS (and MIPSEL) ?

For me it did not work but I could see if I can add that in.

(From a very long time ago, I have some patches based on the debian MIPS 
support but I never managed to find time to upstream them, so this is 
great to finally see!)

Luke
  
Mark Wielaard May 21, 2023, 9:13 p.m. UTC | #6
Hi Ying,

On Tue, May 16, 2023 at 02:38:45PM +0800, Ying Huang wrote:
> 在 2023/5/9 23:15, Mark Wielaard 写道:
> > On Tue, 2023-04-11 at 16:12 +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.
> > Is there a spec that describes this?
>    
> 
>  references:
> 
>     https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf
> 
>     Page40 && Page41

Thanks. Interesting. If possible please include this URL in a comment.

> > I see you adjusted elf.h to include:
> >
> > +#define ELF64_MIPS_R_TYPE(i)		((i) & 0xff)
> > +#define ELF64_MIPS_R_TYPE2(i)           (((i) >> 8) & 0xff)
> > +#define ELF64_MIPS_R_TYPE3(i)           (((i) >> 16) & 0xff)
> >
> > And various new relocation types for MIPS variants.
> > Our elf.h comes from the glibc project. Have you also submitted these
> > changes to libc-alpha@sourceware.org ?
>     Has submitted.
> 
>     https://sourceware.org/pipermail/libc-alpha/2023-May/148026.html
> 
>     https://sourceware.org/pipermail/libc-alpha/2023-May/148112.html

Thanks. We'll sync them as soon as v3 lands.

>     Has tested on big/little endian machine with big/little endian
> ELF file, all were OK.

Could you post those ELF files somewhere?
Maybe we can add some as test files?

> > It feels like this is in the wrong place and doesn't take into account
> > whether the program itself is running on a big or little endian
> > machine.
> >
> > Maybe I am misunderstanding why this conversion is needed always. But I
> > would have expected a specific conversion function for MIPS for
> > ELF_T_REL and/or ELF_T_RELA (which are currently generic).
>
>     1.Considering that some people directly use the original data instead of the interface function gelf_getrela;
> 
>     2.Because there is only one parameter, so can not modify the macro ELF64_R_TYPE;
> 
>     3.If the mips interface function is added, other packages using libelf will not be compatible with mips, and the place where gelf_getrela is used need be modified.
> 
>     Where do you think is the most suitable place to do mips conversion?

So for the convert_data case in elf_getdata.c I would expect a special
conversion function being defined for ELF_T_REL and ELF_T_RELA. This
normally comes from __elf_xfctstom. I realize now that cannot easily
take an Elf of machine type. But I would expect to have the conversion
be done by a new function that can be assigned to fp in convert_data:

      /* Get the conversion function.  */
      fp = __elf_xfctstom[eclass - 1][type];

I still don't fully understand the need of the code in elf_update. I
assume that is needed in case the file was used with ELF_C_RDWR_MMAP?

Cheers,

Mark
  
Mark Wielaard May 21, 2023, 9:14 p.m. UTC | #7
Hi Ying,

On Tue, May 16, 2023 at 03:34:01PM +0800, Ying Huang wrote:
> 在 2023/5/16 14:46, Ying Huang 写道:
> > >> 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.
> > > Where do these segfaults show up?
> >     The screenshot of the segment error was not uploaded successfully in the last email, upload again.

Sorry, the mailinglist seems to strip the image attachements.

> huangying@Sleepygon:~/elf/elfutils_4$ src/elflint src/nm.o
> Segmentation fault
> huangying@Sleepygon:~/elf/elfutils_4$ src/elflint src/strip.o
> Segmentation fault

When running under gdb, what is the backtrace of the crash?

Thanks,

Mark
  
Ying Huang May 24, 2023, 6:21 a.m. UTC | #8
在 2023/5/22 05:13, Mark Wielaard 写道:
> Hi Ying,
>
> On Tue, May 16, 2023 at 02:38:45PM +0800, Ying Huang wrote:
>> 在 2023/5/9 23:15, Mark Wielaard 写道:
>>> On Tue, 2023-04-11 at 16:12 +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.
>>> Is there a spec that describes this?
>>    
>>
>>  references:
>>
>>     https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf
>>
>>     Page40 && Page41
> Thanks. Interesting. If possible please include this URL in a comment.
    OK.
>
>>> I see you adjusted elf.h to include:
>>>
>>> +#define ELF64_MIPS_R_TYPE(i)		((i) & 0xff)
>>> +#define ELF64_MIPS_R_TYPE2(i)           (((i) >> 8) & 0xff)
>>> +#define ELF64_MIPS_R_TYPE3(i)           (((i) >> 16) & 0xff)
>>>
>>> And various new relocation types for MIPS variants.
>>> Our elf.h comes from the glibc project. Have you also submitted these
>>> changes to libc-alpha@sourceware.org ?
>>     Has submitted.
>>
>>     https://sourceware.org/pipermail/libc-alpha/2023-May/148026.html
>>
>>     https://sourceware.org/pipermail/libc-alpha/2023-May/148112.html
> Thanks. We'll sync them as soon as v3 lands.
>
>>     Has tested on big/little endian machine with big/little endian
>> ELF file, all were OK.
> Could you post those ELF files somewhere?
> Maybe we can add some as test files?
    The ELF files I used were "src/strip.o" which were generated on big/little endian machine.

root@debian-sid-mipsbe:~# readelf -h strip.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          426696 (bytes into file)
  Flags:                             0x80000007, noreorder, pic, cpic, mips64r2
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         41
  Section header string table index: 40
root@debian-sid-mipsbe:~# readelf -h elfutils_debug/src/strip.o
ELF Header:
  Magic:   7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, big endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          215248 (bytes into file)
  Flags:                             0x70001007, noreorder, pic, cpic, o32, mips32r2
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         40
  Section header string table index: 39
root@debian-sid-mipsbe:~#

>>> It feels like this is in the wrong place and doesn't take into account
>>> whether the program itself is running on a big or little endian
>>> machine.
>>>
>>> Maybe I am misunderstanding why this conversion is needed always. But I
>>> would have expected a specific conversion function for MIPS for
>>> ELF_T_REL and/or ELF_T_RELA (which are currently generic).
>>     1.Considering that some people directly use the original data instead of the interface function gelf_getrela;
>>
>>     2.Because there is only one parameter, so can not modify the macro ELF64_R_TYPE;
>>
>>     3.If the mips interface function is added, other packages using libelf will not be compatible with mips, and the place where gelf_getrela is used need be modified.
>>
>>     Where do you think is the most suitable place to do mips conversion?
> So for the convert_data case in elf_getdata.c I would expect a special
> conversion function being defined for ELF_T_REL and ELF_T_RELA. This
> normally comes from __elf_xfctstom. I realize now that cannot easily
> take an Elf of machine type. But I would expect to have the conversion
> be done by a new function that can be assigned to fp in convert_data:
>
>       /* Get the conversion function.  */
>       fp = __elf_xfctstom[eclass - 1][type];
        Maybe I can create a new function named "convert_data_for_mips" and contained the code that added in convert_data?
>
> I still don't fully understand the need of the code in elf_update. I
> assume that is needed in case the file was used with ELF_C_RDWR_MMAP?
>
> Cheers,
>
> Mark

    Because we convert the relocation data for mips64el in elf_getdata.c, eg src/strip, and when we write elf  to file, need confirm the relocation data is in original order bits.

    When file use ELF_C_RDWR_MMAP, only impact whether malloc data_base in convert_data.


    Thanks,

    Ying
  
Ying Huang May 26, 2023, 2:48 a.m. UTC | #9
Hi Mark,

在 2023/5/22 05:14, Mark Wielaard 写道:
> Hi Ying,
>
> On Tue, May 16, 2023 at 03:34:01PM +0800, Ying Huang wrote:
>> 在 2023/5/16 14:46, Ying Huang 写道:
>>>>> 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.
>>>> Where do these segfaults show up?
>>>     The screenshot of the segment error was not uploaded successfully in the last email, upload again.
> Sorry, the mailinglist seems to strip the image attachements.
>
>> huangying@Sleepygon:~/elf/elfutils_4$ src/elflint src/nm.o
>> Segmentation fault
>> huangying@Sleepygon:~/elf/elfutils_4$ src/elflint src/strip.o
>> Segmentation fault
> When running under gdb, what is the backtrace of the crash?
>
> Thanks,
>
> Mark

huangying@Sleepygon:~/elf/elfutils_4$ src/elflint src/nm.o

Segmentation fault (core dumped)

huangying@Sleepygon:~/elf/elfutils_4$ gdb src/elflint

...

(gdb) bt
#0  convert_data (type=ELF_T_RELA, size=24912, data=1, eclass=<optimized out>, scn=0xaad3698f98) at elf_getdata.c:254
#1  __libelf_set_data_list_rdlock (scn=0xaad3698f98, wrlocked=<optimized out>) at elf_getdata.c:515
#2  0x000000fff3862f14 in __elf_getdata_rdlock (scn=0xaad3698f98, data=<optimized out>) at elf_getdata.c:622
#3  0x000000fff3862f54 in elf_getdata (scn=<optimized out>, data=<optimized out>) at elf_getdata.c:640
#4  0x000000aaac571c9c in check_rela (ebl=0xaad369b120, ehdr=0xfffb9451b0, shdr=0xfffb945008, idx=<optimized out>) at elflint.c:1500
#5  0x000000aaac574e40 in check_sections (ebl=0xaad369b120, ehdr=0xfffb9451b0) at elflint.c:4198
#6  0x000000aaac5784ac in process_elf_file (only_one=<optimized out>, size=<optimized out>, fname=<optimized out>, suffix=<optimized out>, prefix=<optimized out>, elf=<optimized out>) at elflint.c:4842
#7  process_file (fd=<optimized out>, elf=<optimized out>, prefix=<optimized out>, suffix=<optimized out>, fname=<optimized out>, size=<optimized out>, only_one=<optimized out>) at elflint.c:241
#8  0x000000aaac5688fc in main (argc=<optimized out>, argv=0xfffb9455d8) at elflint.c:174

...


    If I did not malloc to scn->data_base, would occur Segment fault when we want to operate this space "&scn->data_list.data.d". Because src/elflint use read-mmap method to map file.

    Show 10 lines of code "libelf/elf_getdata.c" starting at line 254:

huangying@Sleepygon:~/elf/elfutils_4$ cat libelf/elf_getdata.c | tail -n +254 | head -n 10
            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));


    Show elflint map method in src/elflint.c:

    /* Create an `Elf' descriptor. */

    Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);


Thanks,

Ying
  

Patch

diff --git a/backends/Makefile.am b/backends/Makefile.am
index f373e5fb..bda1b604 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 \
@@ -100,12 +100,14 @@  loongarch_SRCS = loongarch_init.c loongarch_symbol.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..f70d62e4
--- /dev/null
+++ b/backends/mips_init.c
@@ -0,0 +1,49 @@ 
+/* 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"
+
+/* 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..4f1bd3e6
--- /dev/null
+++ b/backends/mips_symbol.c
@@ -0,0 +1,62 @@ 
+/* 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_TYPE(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.h b/libelf/elf.h
index 4bc0e429..aa903837 100644
--- a/libelf/elf.h
+++ b/libelf/elf.h
@@ -678,6 +678,9 @@  typedef Elf64_Xword	Elf64_Relr;
 
 #define ELF64_R_SYM(i)			((i) >> 32)
 #define ELF64_R_TYPE(i)			((i) & 0xffffffff)
+#define ELF64_MIPS_R_TYPE(i)		((i) & 0xff)
+#define ELF64_MIPS_R_TYPE2(i)           (((i) >> 8) & 0xff)
+#define ELF64_MIPS_R_TYPE3(i)           (((i) >> 16) & 0xff)
 #define ELF64_R_INFO(sym,type)		((((Elf64_Xword) (sym)) << 32) + (type))
 
 /* Program segment header.  */
@@ -1927,11 +1930,69 @@  typedef struct
 #define R_MIPS_TLS_TPREL_HI16	49	/* TP-relative offset, high 16 bits */
 #define R_MIPS_TLS_TPREL_LO16	50	/* TP-relative offset, low 16 bits */
 #define R_MIPS_GLOB_DAT		51
+#define R_MIPS_PC21_S2          60
+/* copy binutils-2.34/elfcpp/mips.h +102 */
+#define R_MIPS_PC26_S2          61
+#define R_MIPS_PC18_S3          62
+#define R_MIPS_PC19_S2          63
+#define R_MIPS_PCHI16           64
+#define R_MIPS_PCLO16           65
+#define R_MIPS16_26             100
+#define R_MIPS16_GPREL          101
+#define R_MIPS16_GOT16          102
+#define R_MIPS16_CALL16         103
+#define R_MIPS16_HI16           104
+#define R_MIPS16_LO16           105
+#define R_MIPS16_TLS_GD         106
+#define R_MIPS16_TLS_LDM        107
+#define R_MIPS16_TLS_DTPREL_HI16 108
+#define R_MIPS16_TLS_DTPREL_LO16 109
+#define R_MIPS16_TLS_GOTTPREL   110
+#define R_MIPS16_TLS_TPREL_HI16 111
+#define R_MIPS16_TLS_TPREL_LO16 112
+#define R_MIPS16_PC16_S1        113
 #define R_MIPS_COPY		126
 #define R_MIPS_JUMP_SLOT        127
+#define R_MIPS_RELATIVE         128
+#define R_MICROMIPS_26_S1       133
+#define R_MICROMIPS_HI16        134
+#define R_MICROMIPS_LO16        135
+#define R_MICROMIPS_GPREL16     136
+#define R_MICROMIPS_LITERAL     137
+#define R_MICROMIPS_GOT16       138
+#define R_MICROMIPS_PC7_S1      139
+#define R_MICROMIPS_PC10_S1     140
+#define R_MICROMIPS_PC16_S1     141
+#define R_MICROMIPS_CALL16      142
+#define R_MICROMIPS_GOT_DISP    145
+#define R_MICROMIPS_GOT_PAGE    146
+#define R_MICROMIPS_GOT_OFST    147
+#define R_MICROMIPS_GOT_HI16    148
+#define R_MICROMIPS_GOT_LO16    149
+#define R_MICROMIPS_SUB         150
+#define R_MICROMIPS_HIGHER      151
+#define R_MICROMIPS_HIGHEST     152
+#define R_MICROMIPS_CALL_HI16   153
+#define R_MICROMIPS_CALL_LO16   154
+#define R_MICROMIPS_SCN_DISP    155
+#define R_MICROMIPS_JALR        156
+#define R_MICROMIPS_HI0_LO16    157
+#define R_MICROMIPS_TLS_GD      162
+#define R_MICROMIPS_TLS_LDM     163
+#define R_MICROMIPS_TLS_DTPREL_HI16  164
+#define R_MICROMIPS_TLS_DTPREL_LO16  165
+#define R_MICROMIPS_TLS_GOTTPREL     166
+#define R_MICROMIPS_TLS_TPREL_HI16   169
+#define R_MICROMIPS_TLS_TPREL_LO16   170
+#define R_MICROMIPS_GPREL7_S2   172
+#define R_MICROMIPS_PC23_S2     173
+#define R_MIPS_PC32             248
+#define R_MIPS_EH               249
+#define R_MIPS_GNU_REL16_S2     250
+#define R_MIPS_GNU_VTINHERIT    253
+#define R_MIPS_GNU_VTENTRY      254
 /* Keep this the last entry.  */
-#define R_MIPS_NUM		128
-
+#define R_MIPS_NUM		255
 /* Legal values for p_type field of Elf32_Phdr.  */
 
 #define PT_MIPS_REGINFO	  0x70000000	/* Register usage information. */
diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c
index 5ebd270f..80f91124 100644
--- a/libelf/elf_getdata.c
+++ b/libelf/elf_getdata.c
@@ -139,13 +139,38 @@  convert_data (Elf_Scn *scn, int eclass,
 	      int data, size_t size, Elf_Type type)
 {
   const size_t align = __libelf_type_align (eclass, type);
+  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);
 
   /* Do we need to convert the data and/or adjust for alignment?  */
   if (data == MY_ELFDATA || type == ELF_T_BYTE)
     {
       if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0)
-	/* No need to copy, we can use the raw data.  */
-	scn->data_base = scn->rawdata_base;
+        {
+	  /* 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. */
+	  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)
+	    {
+	      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
+	    /* No need to copy, we can use the raw data.  */
+	    scn->data_base = scn->rawdata_base;
+        }
       else
 	{
 	  scn->data_base = malloc (size);
@@ -174,7 +199,28 @@  convert_data (Elf_Scn *scn, int eclass,
 	 function to directly access the data elements.  */
       char *rawdata_source;
       if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0)
-	rawdata_source = scn->rawdata_base;
+        {
+	  /* 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. */
+	  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)
+	    {
+	      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);
+	    }
+	  else
+	    rawdata_source = scn->rawdata_base;
+	}
       else
 	{
 	  rawdata_source = malloc (size);
@@ -205,6 +251,50 @@  convert_data (Elf_Scn *scn, int eclass,
   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. */
+  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)
+    {
+      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;
+             }
+         }
+     }
 }
 
 
diff --git a/libelf/elf_update.c b/libelf/elf_update.c
index 56af3a1c..11027c38 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: