Fix the LoongArch support code and some more (#483)
authorWÁNG Xuěruì <1175567+xen0n@users.noreply.github.com>
Wed, 6 Sep 2023 12:38:41 +0000 (20:38 +0800)
committerGitHub <noreply@github.com>
Wed, 6 Sep 2023 12:38:41 +0000 (05:38 -0700)
* Fix LoongArch support in dwarfdump.py

The e_machine constant is EM_LOONGARCH, and the emulation name is just
elf{32,64}-loongarch without the endian prefix.

Fixes: 6c36d79 ("add support for loongarch64 to dwarfdump (#458)")
Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
* Fix the EF_LOONGARCH_* symbol names

The current code gets the logic right, but not the symbol names. Fix
them for consistency with the canonical definition that's binutils.

Fixes: 2059475 ("Add support for LoongArch (#470)")
Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
* Fix a missing description string in elffile.py for LoongArch

Fixes: 2059475 ("Add support for LoongArch (#470)")
Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
* Provide EF_LARCH_* name aliases for the EF_LOONGARCH_* constants

Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
* Add definitions for LoongArch relocations

Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
* Add support for basic 32- and 64-bit LoongArch relocations

Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
* scripts/readelf.py: Properly format control chars in symbol names

This is necessary to match readelf behavior on fake symbol names, that
usually look like "L0^A" when rendered (being "L0\x01" in reality).

Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
* scripts/readelf.py: Fix register display order in _dump_debug_frames_interp

According to binutils sources (function frame_display_row in
binutils/dwarf.c), the apparent ordering of the ra register after other
registers is merely a side effect of most architectures allocating a
larger DWARF register number for their respective ra registers. This has
no effect on all readelf test cases, but is necessary for a future
LoongArch test binary to pass comparisons.

Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
* Add test program and artifact covering basic LoongArch relocations

Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
---------

Signed-off-by: WANG Xuerui <xen0n@gentoo.org>
elftools/elf/constants.py
elftools/elf/descriptions.py
elftools/elf/elffile.py
elftools/elf/enums.py
elftools/elf/relocation.py
scripts/dwarfdump.py
scripts/readelf.py
test/testfiles_for_readelf/loongarch-relocs.c [new file with mode: 0644]
test/testfiles_for_readelf/loongarch64-relocs.o.elf [new file with mode: 0644]

index d3cb3a29d8884dc6738291cbbb2d8dba43c0d09a..567f1e3e8923ec9741e6b91dfe39fcac0cafd668 100644 (file)
@@ -60,13 +60,22 @@ class E_FLAGS(object):
     EF_RISCV_RVE=0x00000008
     EF_RISCV_TSO=0x00000010
 
-    EF_LOONGARCH_ABI=0x000000C0
-    EF_LOONGARCH_ABI_V0=0x00000000
-    EF_LOONGARCH_ABI_V1=0x00000040
-    EF_LOONGARCH_FLOAT_ABI=0x00000003
-    EF_LOONGARCH_FLOAT_ABI_SOFT=0x00000001
-    EF_LOONGARCH_FLOAT_ABI_SINGLE=0x00000002
-    EF_LOONGARCH_FLOAT_ABI_DOUBLE=0x00000003
+    EF_LOONGARCH_OBJABI_MASK=0x000000C0
+    EF_LOONGARCH_OBJABI_V0=0x00000000
+    EF_LOONGARCH_OBJABI_V1=0x00000040
+    EF_LOONGARCH_ABI_MODIFIER_MASK=0x00000007
+    EF_LOONGARCH_ABI_SOFT_FLOAT=0x00000001
+    EF_LOONGARCH_ABI_SINGLE_FLOAT=0x00000002
+    EF_LOONGARCH_ABI_DOUBLE_FLOAT=0x00000003
+    # The names in the glibc elf.h say "LARCH" instead of "LOONGARCH",
+    # provide these names for users' convenience.
+    EF_LARCH_OBJABI_MASK = EF_LOONGARCH_OBJABI_MASK
+    EF_LARCH_OBJABI_V0 = EF_LOONGARCH_OBJABI_V0
+    EF_LARCH_OBJABI_V1 = EF_LOONGARCH_OBJABI_V1
+    EF_LARCH_ABI_MODIFIER_MASK = EF_LOONGARCH_ABI_MODIFIER_MASK
+    EF_LARCH_ABI_SOFT_FLOAT = EF_LOONGARCH_ABI_SOFT_FLOAT
+    EF_LARCH_ABI_SINGLE_FLOAT = EF_LOONGARCH_ABI_SINGLE_FLOAT
+    EF_LARCH_ABI_DOUBLE_FLOAT = EF_LOONGARCH_ABI_DOUBLE_FLOAT
 
 class E_FLAGS_MASKS(object):
     """Masks to be used for convenience when working with E_FLAGS
index 915521041050bea5e9b9ed47776dd61df390dbf1..8458461a5857d1bd1ee98054f7ade314b8262339 100644 (file)
@@ -11,7 +11,7 @@ from .enums import (
     ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64,
     ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_PPC64,
     ENUM_RELOC_TYPE_MIPS, ENUM_ATTR_TAG_ARM, ENUM_ATTR_TAG_RISCV,
-    ENUM_DT_FLAGS, ENUM_DT_FLAGS_1)
+    ENUM_RELOC_TYPE_LOONGARCH, ENUM_DT_FLAGS, ENUM_DT_FLAGS_1)
 from .constants import (
     P_FLAGS, RH_FLAGS, SH_FLAGS, SUNW_SYMINFO_FLAGS, VER_FLAGS)
 from ..common.utils import bytes2hex
@@ -152,6 +152,8 @@ def describe_reloc_type(x, elffile):
         return _DESCR_RELOC_TYPE_PPC64.get(x, _unknown)
     elif arch == 'MIPS':
         return _DESCR_RELOC_TYPE_MIPS.get(x, _unknown)
+    elif arch == 'LoongArch':
+        return _DESCR_RELOC_TYPE_LOONGARCH.get(x, _unknown)
     else:
         return 'unrecognized: %-7x' % (x & 0xFFFFFFFF)
 
@@ -690,6 +692,7 @@ _DESCR_RELOC_TYPE_ARM = _reverse_dict(ENUM_RELOC_TYPE_ARM)
 _DESCR_RELOC_TYPE_AARCH64 = _reverse_dict(ENUM_RELOC_TYPE_AARCH64)
 _DESCR_RELOC_TYPE_PPC64 = _reverse_dict(ENUM_RELOC_TYPE_PPC64)
 _DESCR_RELOC_TYPE_MIPS = _reverse_dict(ENUM_RELOC_TYPE_MIPS)
+_DESCR_RELOC_TYPE_LOONGARCH = _reverse_dict(ENUM_RELOC_TYPE_LOONGARCH)
 
 _low_priority_D_TAG = (
     # these are 'meta-tags' marking semantics of numeric ranges of the enum
index 0a945c6b6f4cff0f3dd06f211d62dbbc3279c8ce..f9fc0b35544ed26806c52289ac75f88b9e9f12de 100644 (file)
@@ -533,6 +533,7 @@ class ELFFile(object):
             'EM_RISCV'         : 'RISC-V',
             'EM_BPF'           : 'Linux BPF - in-kernel virtual machine',
             'EM_CSKY'          : 'C-SKY',
+            'EM_LOONGARCH'     : 'LoongArch',
             'EM_FRV'           : 'Fujitsu FR-V'
         }
 
index 4400310aacdec800bb49727df95e6b978576080f..24c2fd0b76e362ac530e9b23f94a95bae758c5cf 100644 (file)
@@ -831,6 +831,109 @@ ENUM_RELOC_TYPE_BPF = dict(
     _default_=Pass,
 )
 
+# https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc
+ENUM_RELOC_TYPE_LOONGARCH = dict(
+    R_LARCH_NONE=0,
+    R_LARCH_32=1,
+    R_LARCH_64=2,
+    R_LARCH_RELATIVE=3,
+    R_LARCH_COPY=4,
+    R_LARCH_JUMP_SLOT=5,
+    R_LARCH_TLS_DTPMOD32=6,
+    R_LARCH_TLS_DTPMOD64=7,
+    R_LARCH_TLS_DTPREL32=8,
+    R_LARCH_TLS_DTPREL64=9,
+    R_LARCH_TLS_TPREL32=10,
+    R_LARCH_TLS_TPREL64=11,
+    R_LARCH_IRELATIVE=12,
+    R_LARCH_MARK_LA=20,
+    R_LARCH_MARK_PCREL=21,
+    R_LARCH_SOP_PUSH_PCREL=22,
+    R_LARCH_SOP_PUSH_ABSOLUTE=23,
+    R_LARCH_SOP_PUSH_DUP=24,
+    R_LARCH_SOP_PUSH_GPREL=25,
+    R_LARCH_SOP_PUSH_TLS_TPREL=26,
+    R_LARCH_SOP_PUSH_TLS_GOT=27,
+    R_LARCH_SOP_PUSH_TLS_GD=28,
+    R_LARCH_SOP_PUSH_PLT_PCREL=29,
+    R_LARCH_SOP_ASSERT=30,
+    R_LARCH_SOP_NOT=31,
+    R_LARCH_SOP_SUB=32,
+    R_LARCH_SOP_SL=33,
+    R_LARCH_SOP_SR=34,
+    R_LARCH_SOP_ADD=35,
+    R_LARCH_SOP_AND=36,
+    R_LARCH_SOP_IF_ELSE=37,
+    R_LARCH_SOP_POP_32_S_10_5=38,
+    R_LARCH_SOP_POP_32_U_10_12=39,
+    R_LARCH_SOP_POP_32_S_10_12=40,
+    R_LARCH_SOP_POP_32_S_10_16=41,
+    R_LARCH_SOP_POP_32_S_10_16_S2=42,
+    R_LARCH_SOP_POP_32_S_5_20=43,
+    R_LARCH_SOP_POP_32_S_0_5_10_16_S2=44,
+    R_LARCH_SOP_POP_32_S_0_10_10_16_S2=45,
+    R_LARCH_SOP_POP_32_U=46,
+    R_LARCH_ADD8=47,
+    R_LARCH_ADD16=48,
+    R_LARCH_ADD24=49,
+    R_LARCH_ADD32=50,
+    R_LARCH_ADD64=51,
+    R_LARCH_SUB8=52,
+    R_LARCH_SUB16=53,
+    R_LARCH_SUB24=54,
+    R_LARCH_SUB32=55,
+    R_LARCH_SUB64=56,
+    R_LARCH_GNU_VTINHERIT=57,
+    R_LARCH_GNU_VTENTRY=58,
+    R_LARCH_B16=64,
+    R_LARCH_B21=65,
+    R_LARCH_B26=66,
+    R_LARCH_ABS_HI20=67,
+    R_LARCH_ABS_LO12=68,
+    R_LARCH_ABS64_LO20=69,
+    R_LARCH_ABS64_HI12=70,
+    R_LARCH_PCALA_HI20=71,
+    R_LARCH_PCALA_LO12=72,
+    R_LARCH_PCALA64_LO20=73,
+    R_LARCH_PCALA64_HI12=74,
+    R_LARCH_GOT_PC_HI20=75,
+    R_LARCH_GOT_PC_LO12=76,
+    R_LARCH_GOT64_PC_LO20=77,
+    R_LARCH_GOT64_PC_HI12=78,
+    R_LARCH_GOT_HI20=79,
+    R_LARCH_GOT_LO12=80,
+    R_LARCH_GOT64_LO20=81,
+    R_LARCH_GOT64_HI12=82,
+    R_LARCH_TLS_LE_HI20=83,
+    R_LARCH_TLS_LE_LO12=84,
+    R_LARCH_TLS_LE64_LO20=85,
+    R_LARCH_TLS_LE64_HI12=86,
+    R_LARCH_TLS_IE_PC_HI20=87,
+    R_LARCH_TLS_IE_PC_LO12=88,
+    R_LARCH_TLS_IE64_PC_LO20=89,
+    R_LARCH_TLS_IE64_PC_HI12=90,
+    R_LARCH_TLS_IE_HI20=91,
+    R_LARCH_TLS_IE_LO12=92,
+    R_LARCH_TLS_IE64_LO20=93,
+    R_LARCH_TLS_IE64_HI12=94,
+    R_LARCH_TLS_LD_PC_HI20=95,
+    R_LARCH_TLS_LD_HI20=96,
+    R_LARCH_TLS_GD_PC_HI20=97,
+    R_LARCH_TLS_GD_HI20=98,
+    R_LARCH_32_PCREL=99,
+    R_LARCH_RELAX=100,
+    R_LARCH_DELETE=101,
+    R_LARCH_ALIGN=102,
+    R_LARCH_PCREL20_S2=103,
+    R_LARCH_CFA=104,
+    R_LARCH_ADD6=105,
+    R_LARCH_SUB6=106,
+    R_LARCH_ADD_ULEB128=107,
+    R_LARCH_SUB_ULEB128=108,
+    R_LARCH_64_PCREL=109,
+    _default_=Pass,
+)
+
 # Sunw Syminfo Bound To special values
 ENUM_SUNW_SYMINFO_BOUNDTO = dict(
     SYMINFO_BT_SELF=0xffff,
index c167368dec517019473b514df3188fe184c2ffcd..49702f0662bc4a83512d6ff7476f10de2b1170be 100644 (file)
@@ -14,7 +14,7 @@ from .sections import Section
 from .enums import (
     ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64, ENUM_RELOC_TYPE_MIPS,
     ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_PPC64,
-    ENUM_RELOC_TYPE_BPF, ENUM_D_TAG)
+    ENUM_RELOC_TYPE_BPF, ENUM_RELOC_TYPE_LOONGARCH, ENUM_D_TAG)
 from ..construct import Container
 
 
@@ -259,6 +259,11 @@ class RelocationHandler(object):
             recipe = self._RELOCATION_RECIPES_PPC64.get(reloc_type, None)
         elif self.elffile.get_machine_arch() == 'Linux BPF - in-kernel virtual machine':
             recipe = self._RELOCATION_RECIPES_EBPF.get(reloc_type, None)
+        elif self.elffile.get_machine_arch() == 'LoongArch':
+            if not reloc.is_RELA():
+                raise ELFRelocationError(
+                    'Unexpected REL relocation for LoongArch: %s' % reloc)
+            recipe = self._RELOCATION_RECIPES_LOONGARCH.get(reloc_type, None)
 
         if recipe is None:
             raise ELFRelocationError(
@@ -273,6 +278,10 @@ class RelocationHandler(object):
             value_struct = self.elffile.structs.Elf_word('')
         elif recipe.bytesize == 8:
             value_struct = self.elffile.structs.Elf_word64('')
+        elif recipe.bytesize == 1:
+            value_struct = self.elffile.structs.Elf_byte('')
+        elif recipe.bytesize == 2:
+            value_struct = self.elffile.structs.Elf_half('')
         else:
             raise ELFRelocationError('Invalid bytesize %s for relocation' %
                     recipe.bytesize)
@@ -322,6 +331,9 @@ class RelocationHandler(object):
     def _reloc_calc_sym_plus_addend_pcrel(value, sym_value, offset, addend=0):
         return sym_value + addend - offset
 
+    def _reloc_calc_value_minus_sym_addend(value, sym_value, offset, addend=0):
+        return value - sym_value - addend
+
     def _arm_reloc_calc_sym_plus_value_pcrel(value, sym_value, offset, addend=0):
         return sym_value // 4 + value - offset // 4
 
@@ -416,4 +428,46 @@ class RelocationHandler(object):
             bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
     }
 
+    # https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc
+    _RELOCATION_RECIPES_LOONGARCH = {
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_NONE']: _RELOCATION_RECIPE_TYPE(
+            bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_32']: _RELOCATION_RECIPE_TYPE(
+            bytesize=4, has_addend=True,
+            calc_func=_reloc_calc_sym_plus_addend),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_64']: _RELOCATION_RECIPE_TYPE(
+            bytesize=8, has_addend=True,
+            calc_func=_reloc_calc_sym_plus_addend),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_ADD8']: _RELOCATION_RECIPE_TYPE(
+            bytesize=1, has_addend=True,
+            calc_func=_reloc_calc_sym_plus_value),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_SUB8']: _RELOCATION_RECIPE_TYPE(
+            bytesize=1, has_addend=True,
+            calc_func=_reloc_calc_value_minus_sym_addend),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_ADD16']: _RELOCATION_RECIPE_TYPE(
+            bytesize=2, has_addend=True,
+            calc_func=_reloc_calc_sym_plus_value),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_SUB16']: _RELOCATION_RECIPE_TYPE(
+            bytesize=2, has_addend=True,
+            calc_func=_reloc_calc_value_minus_sym_addend),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_ADD32']: _RELOCATION_RECIPE_TYPE(
+            bytesize=4, has_addend=True,
+            calc_func=_reloc_calc_sym_plus_value),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_SUB32']: _RELOCATION_RECIPE_TYPE(
+            bytesize=4, has_addend=True,
+            calc_func=_reloc_calc_value_minus_sym_addend),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_ADD64']: _RELOCATION_RECIPE_TYPE(
+            bytesize=8, has_addend=True,
+            calc_func=_reloc_calc_sym_plus_value),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_SUB64']: _RELOCATION_RECIPE_TYPE(
+            bytesize=8, has_addend=True,
+            calc_func=_reloc_calc_value_minus_sym_addend),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_32_PCREL']: _RELOCATION_RECIPE_TYPE(
+            bytesize=4, has_addend=True,
+            calc_func=_reloc_calc_sym_plus_addend_pcrel),
+        ENUM_RELOC_TYPE_LOONGARCH['R_LARCH_64_PCREL']: _RELOCATION_RECIPE_TYPE(
+            bytesize=8, has_addend=True,
+            calc_func=_reloc_calc_sym_plus_addend_pcrel),
+    }
+
 
index e1148832d450e60265227767f92700546a1a8870..fec7524a806c6851049d780b4f74bdccc9ec6dc9 100644 (file)
@@ -342,7 +342,7 @@ class ReadElf(object):
         self.elffile = ELFFile(file)
         self.output = output
         self._dwarfinfo = self.elffile.get_dwarf_info()
-        arches = {"EM_386": "i386", "EM_X86_64": "x86-64", "EM_ARM": "littlearm", "EM_AARCH64": "littleaarch64", "EM_LOONGARCH64": "loongarch64", "EM_RISCV": "littleriscv", "EM_MIPS": "mips"}
+        arches = {"EM_386": "i386", "EM_X86_64": "x86-64", "EM_ARM": "littlearm", "EM_AARCH64": "littleaarch64", "EM_LOONGARCH": "loongarch", "EM_RISCV": "littleriscv", "EM_MIPS": "mips"}
         arch = arches[self.elffile['e_machine']]
         bits = self.elffile.elfclass
         self._emitline("%s:    file format elf%d-%s" % (filename, bits, arch))
index a58085b41c7b184c24e470749d84023f691c9ca8..6bd5cf3c9f3c1485a3259df874c998bee06c1284 100755 (executable)
@@ -9,6 +9,7 @@
 #-------------------------------------------------------------------------------
 import argparse
 import os, sys
+import re
 import string
 import traceback
 import itertools
@@ -95,6 +96,13 @@ def _get_cu_base(cu):
     else:
         raise ValueError("Can't find the base IP (low_pc) for a CU")
 
+# Matcher for all control characters, for transforming them into "^X" form when
+# formatting symbol names for display.
+_CONTROL_CHAR_RE = re.compile(r'[\x01-\x1f]')
+
+def _format_symbol_name(s):
+    return _CONTROL_CHAR_RE.sub(lambda match: '^' + chr(0x40 + ord(match[0])), s)
+
 class ReadElf(object):
     """ display_* methods are used to emit output into the output stream
     """
@@ -260,15 +268,15 @@ class ReadElf(object):
                 description += ", quad-float ABI"
 
         elif self.elffile['e_machine'] == "EM_LOONGARCH":
-            if (flags & E_FLAGS.EF_LOONGARCH_FLOAT_ABI) == E_FLAGS.EF_LOONGARCH_FLOAT_ABI_SOFT:
+            if (flags & E_FLAGS.EF_LOONGARCH_ABI_MODIFIER_MASK) == E_FLAGS.EF_LOONGARCH_ABI_SOFT_FLOAT:
                 description += ", SOFT-FLOAT"
-            if (flags & E_FLAGS.EF_LOONGARCH_FLOAT_ABI) == E_FLAGS.EF_LOONGARCH_FLOAT_ABI_SINGLE:
+            if (flags & E_FLAGS.EF_LOONGARCH_ABI_MODIFIER_MASK) == E_FLAGS.EF_LOONGARCH_ABI_SINGLE_FLOAT:
                 description += ", SINGLE-FLOAT"
-            if (flags & E_FLAGS.EF_LOONGARCH_FLOAT_ABI) == E_FLAGS.EF_LOONGARCH_FLOAT_ABI_DOUBLE:
+            if (flags & E_FLAGS.EF_LOONGARCH_ABI_MODIFIER_MASK) == E_FLAGS.EF_LOONGARCH_ABI_DOUBLE_FLOAT:
                 description += ", DOUBLE-FLOAT"
-            if (flags & E_FLAGS.EF_LOONGARCH_ABI) == E_FLAGS.EF_LOONGARCH_ABI_V0:
+            if (flags & E_FLAGS.EF_LOONGARCH_OBJABI_MASK) == E_FLAGS.EF_LOONGARCH_OBJABI_V0:
                 description += ", OBJ-v0"
-            if (flags & E_FLAGS.EF_LOONGARCH_ABI) == E_FLAGS.EF_LOONGARCH_ABI_V1:
+            if (flags & E_FLAGS.EF_LOONGARCH_OBJABI_MASK) == E_FLAGS.EF_LOONGARCH_OBJABI_V1:
                 description += ", OBJ-v1"
 
         return description
@@ -495,7 +503,7 @@ class ReadElf(object):
                     describe_symbol_shndx(self._get_symbol_shndx(symbol,
                                                                  nsym,
                                                                  section_index)),
-                    symbol_name,
+                    _format_symbol_name(symbol_name),
                     version_info))
 
     def display_dynamic_tags(self):
@@ -632,7 +640,7 @@ class ReadElf(object):
                         self._format_hex(
                             symbol['st_value'],
                             fullhex=True, lead0x=False),
-                        symbol_name))
+                        _format_symbol_name(symbol_name)))
                     if section.is_RELA():
                         self._emit(' %s %x' % (
                             '+' if rel['r_addend'] >= 0 else '-',
@@ -1451,24 +1459,20 @@ class ReadElf(object):
 
             # Look at the registers the decoded table describes.
             # We build reg_order here to match readelf's order. In particular,
-            # registers are sorted by their number, and the register matching
-            # ra_regnum is always listed last with a special heading.
+            # registers are sorted by their number, so that the register
+            # matching ra_regnum is usually listed last with a special heading.
+            # (LoongArch is a notable exception in that its return register's
+            # DWARF register number is not greater than other GPRs.)
             decoded_table = entry.get_decoded()
-            reg_order = sorted(filter(
-                lambda r: r != ra_regnum,
-                decoded_table.reg_order))
+            reg_order = sorted(decoded_table.reg_order)
             if len(decoded_table.reg_order):
-
                 # Headings for the registers
                 for regnum in reg_order:
+                    if regnum == ra_regnum:
+                        self._emit('ra      ')
+                        continue
                     self._emit('%-6s' % describe_reg_name(regnum))
-                self._emitline('ra      ')
-
-                # Now include ra_regnum in reg_order to print its values
-                # similarly to the other registers.
-                reg_order.append(ra_regnum)
-            else:
-                self._emitline()
+            self._emitline()
 
             for line in decoded_table.table:
                 self._emit(self._format_hex(
diff --git a/test/testfiles_for_readelf/loongarch-relocs.c b/test/testfiles_for_readelf/loongarch-relocs.c
new file mode 100644 (file)
index 0000000..ad347d8
--- /dev/null
@@ -0,0 +1,18 @@
+/* This source was compiled for LoongArch64.
+   loongarch64-unknown-linux-gnu-gcc -c -o loongarch64-relocs.o.elf loongarch-relocs.c -g
+   Upstream support for LoongArch32 is not yet mature, so it is not covered.
+*/
+
+extern struct {
+  int i, j;
+} data;
+
+extern int bar (void);
+
+int
+foo (int a)
+{
+  data.i += a;
+  data.j -= bar();
+  return 0;
+}
diff --git a/test/testfiles_for_readelf/loongarch64-relocs.o.elf b/test/testfiles_for_readelf/loongarch64-relocs.o.elf
new file mode 100644 (file)
index 0000000..12fafa2
Binary files /dev/null and b/test/testfiles_for_readelf/loongarch64-relocs.o.elf differ