From: WÁNG Xuěruì <1175567+xen0n@users.noreply.github.com> Date: Wed, 6 Sep 2023 12:38:41 +0000 (+0800) Subject: Fix the LoongArch support code and some more (#483) X-Git-Tag: v0.30~1 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=20cc45cea34190b607f9f05f2154978247793166;p=pyelftools.git Fix the LoongArch support code and some more (#483) * 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 * 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 * Fix a missing description string in elffile.py for LoongArch Fixes: 2059475 ("Add support for LoongArch (#470)") Signed-off-by: WANG Xuerui * Provide EF_LARCH_* name aliases for the EF_LOONGARCH_* constants Signed-off-by: WANG Xuerui * Add definitions for LoongArch relocations Signed-off-by: WANG Xuerui * Add support for basic 32- and 64-bit LoongArch relocations Signed-off-by: WANG Xuerui * 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 * 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 * Add test program and artifact covering basic LoongArch relocations Signed-off-by: WANG Xuerui --------- Signed-off-by: WANG Xuerui --- diff --git a/elftools/elf/constants.py b/elftools/elf/constants.py index d3cb3a2..567f1e3 100644 --- a/elftools/elf/constants.py +++ b/elftools/elf/constants.py @@ -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 diff --git a/elftools/elf/descriptions.py b/elftools/elf/descriptions.py index 9155210..8458461 100644 --- a/elftools/elf/descriptions.py +++ b/elftools/elf/descriptions.py @@ -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 diff --git a/elftools/elf/elffile.py b/elftools/elf/elffile.py index 0a945c6..f9fc0b3 100644 --- a/elftools/elf/elffile.py +++ b/elftools/elf/elffile.py @@ -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' } diff --git a/elftools/elf/enums.py b/elftools/elf/enums.py index 4400310..24c2fd0 100644 --- a/elftools/elf/enums.py +++ b/elftools/elf/enums.py @@ -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, diff --git a/elftools/elf/relocation.py b/elftools/elf/relocation.py index c167368..49702f0 100644 --- a/elftools/elf/relocation.py +++ b/elftools/elf/relocation.py @@ -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), + } + diff --git a/scripts/dwarfdump.py b/scripts/dwarfdump.py index e114883..fec7524 100644 --- a/scripts/dwarfdump.py +++ b/scripts/dwarfdump.py @@ -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)) diff --git a/scripts/readelf.py b/scripts/readelf.py index a58085b..6bd5cf3 100755 --- a/scripts/readelf.py +++ b/scripts/readelf.py @@ -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 index 0000000..ad347d8 --- /dev/null +++ b/test/testfiles_for_readelf/loongarch-relocs.c @@ -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 index 0000000..12fafa2 Binary files /dev/null and b/test/testfiles_for_readelf/loongarch64-relocs.o.elf differ