[PATCH v2 4/6] Readelf for nanoMIPS.
Tsing
lei.wang@oss.cipunited.com
Fri Jul 24 10:30:56 GMT 2026
From: tsing <lei.wang@oss.cipunited.com>
binutils/
* readelf.c (guess_is_rela): Add EM_NANOMIPS.
(get_machine_name): Likewise.
(dump_relocations): Add support for nanomips relocations.
(get_machine_flags): Add support for nanomips flags.
(is_32bit_abs_reloc): Add R_NANOMIPS_32.
(is_32bit_pcrel_reloc): Add R_NANOMIPS_PC32.
(is_64bit_abs_reloc): Add R_NANOMIPS_64.
(is_16bit_abs_reloc): Add R_NANOMIPS_UNSIGNED_16.
(is_none_reloc): Add R_NANOMIPS_NONE.
---
binutils/readelf.c | 422 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 422 insertions(+)
diff --git a/binutils/readelf.c b/binutils/readelf.c
index a52fe2b8d63..ec9f5ebb484 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -141,6 +141,7 @@
#include "elf/moxie.h"
#include "elf/mt.h"
#include "elf/msp430.h"
+#include "elf/nanomips.h"
#include "elf/nds32.h"
#include "elf/nfp.h"
#include "elf/nios2.h"
@@ -1319,6 +1320,7 @@ guess_is_rela (unsigned int e_machine)
case EM_MSP430:
case EM_MSP430_OLD:
case EM_MT:
+ case EM_NANOMIPS:
case EM_NDS32:
case EM_NIOS32:
case EM_OR1K:
@@ -2687,6 +2689,10 @@ dump_relocations (Filedata * filedata,
case EM_AMDGPU:
rtype = elf_amdgpu_reloc_type (type);
break;
+
+ case EM_NANOMIPS:
+ rtype = elf_nanomips_reloc_type (type);
+ break;
}
char *symbol_name = NULL;
@@ -3812,6 +3818,7 @@ get_machine_name (unsigned e_machine)
case EM_CEVA: return "CEVA Processor Architecture Family";
case EM_CEVA_X2: return "CEVA X2 Processor Family";
case EM_BPF: return "Linux BPF";
+ case EM_NANOMIPS: return "nanoMIPS";
case EM_GRAPHCORE_IPU: return "Graphcore Intelligent Processing Unit";
case EM_IMG1: return "Imagination Technologies";
/* 250 */
@@ -5625,6 +5632,38 @@ get_machine_flags (Filedata * filedata, unsigned e_flags, unsigned e_machine)
out = decode_MSP430_machine_flags (out, e_flags);
break;
+ case EM_NANOMIPS:
+ if (e_flags & EF_NANOMIPS_PIC)
+ strcat (buf, ", pic");
+
+ if (e_flags & EF_NANOMIPS_32BITMODE)
+ strcat (buf, ", 32bitmode");
+
+ switch ((e_flags & EF_NANOMIPS_MACH))
+ {
+ default: strcat (buf, _(", unknown CPU")); break;
+ }
+
+ switch ((e_flags & EF_NANOMIPS_ABI))
+ {
+ case E_NANOMIPS_ABI_P32: strcat (buf, ", p32"); break;
+ case E_NANOMIPS_ABI_P64: strcat (buf, ", p64"); break;
+ case 0:
+ /* We simply ignore the field in this case to avoid confusion:
+ MIPS ELF does not specify EF_MIPS_ABI, it is a GNU extension.
+ This means it is likely to be an o32 file, but not for
+ sure. */
+ break;
+ default: strcat (buf, _(", unknown ABI")); break;
+ }
+
+ switch ((e_flags & EF_NANOMIPS_ARCH))
+ {
+ case E_NANOMIPS_ARCH_32R6: strcat (buf, ", nanomips32r6"); break;
+ case E_NANOMIPS_ARCH_64R6: strcat (buf, ", nanomips64r6"); break;
+ default: strcat (buf, _(", unknown ISA")); break;
+ }
+
case EM_Z80:
out = decode_Z80_machine_flags (out, e_flags);
break;
@@ -16077,6 +16116,35 @@ target_specific_reloc_handling (Filedata *filedata,
}
break;
}
+ case EM_NANOMIPS:
+ {
+ static Elf_Internal_Sym * saved_sym = NULL;
+
+ if (reloc == NULL)
+ {
+ saved_sym = NULL;
+ return true;
+ }
+
+ if (reloc_type == 3)
+ {
+ saved_sym = symtab + sym_index;
+ bfd_vma value;
+
+ if (sym_index >= num_syms)
+ error (_("nanomips reloc contains invalid symbol index %lu\n"),
+ sym_index);
+ else
+ {
+ value = reloc->r_addend - saved_sym->st_value;
+ reloc++;
+ reloc->r_addend += value;
+ return true;
+ }
+ break;
+ }
+ break;
+ }
}
return false;
@@ -16210,6 +16278,8 @@ is_32bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
return reloc_type == 1; /* R_MSP430_32 or R_MSP320_ABS32. */
case EM_MT:
return reloc_type == 2; /* R_MT_32. */
+ case EM_NANOMIPS:
+ return reloc_type == 1; /* R_NANOMIPS_32. */
case EM_NDS32:
return reloc_type == 20; /* R_NDS32_32_RELA. */
case EM_ALTERA_NIOS2:
@@ -16332,6 +16402,8 @@ is_32bit_pcrel_reloc (Filedata * filedata, unsigned int reloc_type)
return reloc_type == 99; /* R_LARCH_32_PCREL. */
case EM_MICROBLAZE:
return reloc_type == 2; /* R_MICROBLAZE_32_PCREL. */
+ case EM_NANOMIPS:
+ return reloc_type == 248; /* R_NANOMIPS_PC32. */
case EM_OR1K:
return reloc_type == 9; /* R_OR1K_32_PCREL. */
case EM_PARISC:
@@ -16421,6 +16493,8 @@ is_64bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
return reloc_type == 1; /* R_TILEGX_64. */
case EM_MIPS:
return reloc_type == 18; /* R_MIPS_64. */
+ case EM_NANOMIPS:
+ return reloc_type == 2; /* R_NANOMIPS_64. */
case EM_KVX:
return reloc_type == 3; /* R_KVX_64 */
default:
@@ -16534,6 +16608,8 @@ is_16bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
/* Fall through. */
case EM_MSP430_OLD:
return reloc_type == 5; /* R_MSP430_16_BYTE. */
+ case EM_NANOMIPS:
+ return reloc_type == 7; /* R_NANOMIPS_UNSIGNED_16 */
case EM_NDS32:
return reloc_type == 19; /* R_NDS32_16_RELA. */
case EM_ALTERA_NIOS2:
@@ -16818,6 +16894,7 @@ is_none_reloc (Filedata * filedata, unsigned int reloc_type)
case EM_X86_64: /* R_X86_64_NONE. */
case EM_Z80: /* R_Z80_NONE. */
case EM_WEBASSEMBLY: /* R_WASM32_NONE. */
+ case EM_NANOMIPS: /* R_NANOMIPS_NONE. */
return reloc_type == 0;
case EM_AARCH64:
@@ -19367,6 +19444,23 @@ display_mips_gnu_attribute (const unsigned char * p,
return display_tag_value (tag & 1, p, end);
}
+static unsigned char *
+display_nanomips_gnu_attribute (unsigned char * p,
+ unsigned int tag,
+ const unsigned char * const end)
+{
+ if (tag == Tag_GNU_NANOMIPS_ABI_FP)
+ {
+ int val;
+
+ READ_ULEB (val, p, end);
+ printf (" Tag_GNU_NANOMIPS_ABI_FP: ");
+ return p;
+ }
+
+ return display_tag_value (tag & 1, p, end);
+}
+
static const unsigned char *
display_tic6x_attribute (const unsigned char * p,
const unsigned char * const end)
@@ -21826,6 +21920,331 @@ process_got_section_contents (Filedata * filedata)
return res;
}
+static void
+print_nanomips_ases (unsigned int mask)
+{
+ if (mask & NANOMIPS_ASE_MT)
+ fputs ("\n\tMT ASE", stdout);
+ if (mask & NANOMIPS_ASE_VIRT)
+ fputs ("\n\tVZ ASE", stdout);
+ if ((mask & NANOMIPS_ASE_xNMS) == 0)
+ fputs ("\n\tnanoMIPS subset", stdout);
+ else if (mask == 0)
+ fprintf (stdout, "\n\t%s", _("None"));
+ else if ((mask & ~NANOMIPS_ASE_MASK) != 0)
+ fprintf (stdout, "\n\t%s (%x)", _("Unknown"), mask & ~NANOMIPS_ASE_MASK);
+}
+
+static void
+print_nanomips_isa_ext (unsigned int isa_ext)
+{
+ switch (isa_ext)
+ {
+ case 0:
+ fputs (_("None"), stdout);
+ break;
+ default:
+ fprintf (stdout, "%s (%d)", _("Unknown"), isa_ext);
+ }
+}
+
+static int
+get_nanomips_reg_size (int reg_size)
+{
+ return (get_mips_reg_size (reg_size));
+}
+
+/* DATA points to the contents of a nanoMIPS GOT that starts at VMA PLTGOT.
+ Print the Address, Access and Initial fields of an entry at VMA ADDR
+ and return the VMA of the next entry, or -1 if there was a problem.
+ Does not read from DATA_END or beyond. */
+
+static bfd_vma
+print_nanomips_got_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr,
+ unsigned char * data_end)
+{
+ printf (" ");
+ print_vma (addr, LONG_HEX);
+ printf (" %8d(gp) ", (int) (addr - pltgot));
+
+ if (data == NULL)
+ printf ("%*s", is_32bit_elf ? 8 : 16, _("<unknown>"));
+ else
+ {
+ bfd_vma entry;
+ unsigned char * from = data + addr - pltgot;
+
+ if (from + (is_32bit_elf ? 4 : 8) > data_end)
+ {
+ warn (_("nanoMIPS GOT entry extends beyond the end of available data\n"));
+ printf ("%*s", is_32bit_elf ? 8 : 16, _("<corrupt>"));
+ return (bfd_vma) -1;
+ }
+ else
+ {
+ entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8);
+ print_vma (entry, LONG_HEX);
+ }
+ }
+ return addr + (is_32bit_elf ? 4 : 8);
+}
+
+/* Comparison function to sort relocs by increasing offsets. */
+
+static /* signed */ int
+relcmp (const void *p, const void *q)
+{
+ Elf_Internal_Rela *sp = (Elf_Internal_Rela *) p;
+ Elf_Internal_Rela *sq = (Elf_Internal_Rela *) q;
+
+ return (sp->r_offset > sq->r_offset
+ ? 1
+ : (sp->r_offset < sq->r_offset ? -1 : 0));
+}
+
+/* Pretty-print the nanoMIPS GOT. */
+
+static bool
+print_nanomips_got (Filedata * filedata)
+{
+ Elf_Internal_Shdr *sect = NULL;
+ bfd_vma pltgot = 0;
+ unsigned char *data_end;
+ unsigned char *data;
+ bfd_vma ent = 0;
+ bfd_vma end;
+ int addr_size;
+ int sym_width;
+ struct {
+ Elf_Internal_Rela * rels;
+ unsigned long relsize;
+ unsigned rindex;
+ } rtable[3];
+ int i;
+ enum {REL=0, RELA=1, JMPREL=2};
+
+ /* Clear the relocs. */
+ memset (rtable, 0, sizeof (rtable));
+
+ /* Fetch the GOT. */
+ sect = find_section (filedata, ".got");
+
+ if (sect == NULL)
+ return true;
+
+ /* This is overly complicated in order to handle dynamic relocations as
+ either REL or RELA and to handle the case where jump relocations are
+ embedded within the dynamic relocations section. */
+ if (filedata->dynamic_info[DT_REL] != 0)
+ {
+ if (!slurp_rel_relocs (filedata,
+ offset_from_vma (filedata, filedata->dynamic_info[DT_REL],
+ filedata->dynamic_info[DT_RELENT]),
+ filedata->dynamic_info[DT_RELSZ],
+ &rtable[REL].rels, &rtable[REL].relsize))
+ return false;
+ /* Sort for easy lookup. */
+ qsort (rtable[REL].rels, rtable[REL].relsize,
+ sizeof (Elf_Internal_Rela), relcmp);
+ }
+ if (filedata->dynamic_info[DT_RELA] != 0)
+ {
+ if (!slurp_rel_relocs (filedata,
+ offset_from_vma (filedata, filedata->dynamic_info[DT_RELA],
+ filedata->dynamic_info[DT_RELAENT]),
+ filedata->dynamic_info[DT_RELASZ],
+ &rtable[RELA].rels, &rtable[RELA].relsize))
+ return false;
+ /* Sort for easy lookup. */
+ qsort (rtable[RELA].rels, rtable[RELA].relsize, sizeof (Elf_Internal_Rela), relcmp);
+ }
+ if (filedata->dynamic_info[DT_JMPREL] != 0)
+ {
+ int rent = ((filedata->dynamic_info[DT_PLTREL] == DT_REL)
+ ? filedata->dynamic_info[DT_RELENT] : filedata->dynamic_info[DT_RELAENT]);
+ /* If jump relocations are embedded within regular dynamic relocations,
+ we don't need to read them again. They have already been read above. */
+ if ((filedata->dynamic_info[DT_PLTREL] == DT_REL
+ && (filedata->dynamic_info[DT_JMPREL] < filedata->dynamic_info[DT_REL]
+ || filedata->dynamic_info[DT_JMPREL] >= filedata->dynamic_info[DT_REL] + filedata->dynamic_info[DT_RELSZ]))
+ || (filedata->dynamic_info[DT_PLTREL] == DT_RELA
+ && (filedata->dynamic_info[DT_JMPREL] < filedata->dynamic_info[DT_RELA]
+ || filedata->dynamic_info[DT_JMPREL] >= filedata->dynamic_info[DT_RELA] + filedata->dynamic_info[DT_RELASZ])))
+ {
+ if (!slurp_rel_relocs (filedata,
+ offset_from_vma (filedata, filedata->dynamic_info[DT_JMPREL], rent),
+ filedata->dynamic_info[DT_PLTRELSZ],
+ &rtable[JMPREL].rels, &rtable[JMPREL].relsize))
+ return false;
+ /* Sort for easy lookup. */
+ qsort (rtable[JMPREL].rels, rtable[JMPREL].relsize, sizeof (Elf_Internal_Rela), relcmp);
+ }
+ }
+ /* Temporary hack. Remove when the linker generate DT_JMPREL. */
+ else if (find_section (filedata, ".rel.nanoMIPS.stubs") != NULL)
+ {
+ Elf_Internal_Shdr *jumpsect = find_section (filedata, ".rel.nanoMIPS.stubs");
+ if (!slurp_rel_relocs (filedata,
+ offset_from_vma (filedata, jumpsect->sh_addr,
+ filedata->dynamic_info[DT_RELENT]),
+ jumpsect->sh_size,
+ &rtable[JMPREL].rels, &rtable[JMPREL].relsize))
+ return false;
+ }
+
+ pltgot = sect->sh_addr;
+
+ /* Find relocations corresponding to the beginning of the GOT. */
+ for (i = REL; i <= JMPREL; i++)
+ while (rtable[i].rindex < rtable[i].relsize
+ && rtable[i].rels[rtable[i].rindex].r_offset < pltgot)
+ rtable[i].rindex++;
+
+ ent = pltgot;
+ addr_size = (is_32bit_elf ? 4 : 8);
+ /* Available screen width for symbols is whatever is left over
+ after everything else, including column-separating whitespaces. */
+ sym_width = ((is_32bit_elf ? 80 : 160) - 32 - addr_size * 4);
+ end = pltgot + sect->sh_size;
+
+ data = (unsigned char *) get_data (NULL, filedata, sect->sh_offset,
+ end - pltgot, 1,
+ _("Global Offset Table data"));
+ data_end = data + (end - pltgot);
+
+ printf (_("\nGOT:\n"));
+ printf (_(" GP value: "));
+ print_vma (ent, LONG_HEX);
+ printf ("\n\n");
+
+ /* In a dynamic binary GOT[0] is reserved for the dynamic
+ loader to store the lazy resolver pointer, however in
+ a static binary it may well have been omitted and GOT
+ reduced to a table of addresses. */
+ if (data
+ && data + ent - pltgot + addr_size <= data_end
+ && byte_get (data + ent - pltgot, addr_size) == 0)
+ {
+ printf (_(" Reserved entries:\n"));
+ printf (_(" %*s %*s %*s Purpose\n"),
+ (- addr_size * 2) + 1, _("Address"), 12, _("Access"),
+ (- addr_size * 2) + 1, _("Initial"));
+ ent = print_nanomips_got_entry (data, pltgot, ent, data_end);
+ printf (_(" Lazy stub resolver\n"));
+ if (ent == (bfd_vma) -1)
+ goto sgot_print_fail;
+
+ if (ent == (bfd_vma) -1)
+ goto sgot_print_fail;
+
+ /* Check for the MSB of GOT[1] being set, identifying a
+ GNU object. This entry will be used by some runtime
+ loaders, to store the module pointer. Otherwise this
+ is an ordinary local entry. */
+ if (data
+ && data + ent - pltgot + addr_size <= data_end
+ && (byte_get (data + ent - pltgot, addr_size)
+ >> (addr_size * 8 - 1)) != 0)
+ {
+ printf ("\n");
+ ent = print_nanomips_got_entry (data, pltgot, ent, data_end);
+ printf (_(" Module pointer\n"));
+ if (ent == (bfd_vma) -1)
+ goto sgot_print_fail;
+ }
+ printf ("\n");
+ }
+
+ if (ent < end)
+ {
+ printf (_(" Entries:\n"));
+ printf (_(" %*s %*s %*s %*s Name\n"),
+ (- addr_size * 2) + 1, _("Address"), 12, _("Access"),
+ (- addr_size * 2) + 1, _("Value"), -9, _("Type"));
+ }
+
+ while (ent < end)
+ {
+ Elf_Internal_Rela *rel = NULL;
+ bfd_vma next_ent = print_nanomips_got_entry (data, pltgot,
+ ent, data_end);
+ if (next_ent == (bfd_vma) -1)
+ {
+ ent = (bfd_vma) -1;
+ goto sgot_print_fail;
+ }
+
+ /* Scan all relocations for a match against this GOT slot. */
+ for (i = REL; i <= JMPREL; i++)
+ {
+ while (rel == NULL && rtable[i].rindex < rtable[i].relsize)
+ {
+ if (rtable[i].rels[rtable[i].rindex].r_offset == ent)
+ rel = &rtable[i].rels[rtable[i].rindex];
+ if (rtable[i].rels[rtable[i].rindex].r_offset >= ent)
+ break;
+ rtable[i].rindex ++;
+ }
+ }
+
+ if (rel != NULL)
+ {
+ Elf_Internal_Sym * psym = 0;
+
+ switch (get_reloc_type (filedata, rel->r_info))
+ {
+ case 11: /* R_NANOMIPS_JUMP_SLOT. */
+ printf (" %*s ", -10, "Lazy-stub"); break;
+ case 12: /* R_NANOMIPS_IRELATIVE. */
+ printf (" %*s ", -10, "Indirect"); break;
+ case 10: /* R_NANOMIPS_GLOBAL. */
+ case 1: /* R_NANOMIPS_32. */
+ case 2: /* R_NANOMIPS_64. */
+ printf (" %*s ", -10, "Global"); break;
+ case 9: /* R_NANOMIPS_RELATIVE. */
+ printf (" %*s ", -10, "Local"); break;
+ default:
+ break;
+ }
+
+ if (filedata->dynamic_symbols)
+ {
+ psym = (filedata->dynamic_symbols + get_reloc_symindex (rel->r_info));
+
+ if (valid_dynamic_name (filedata, psym->st_name))
+ print_symbol_name (sym_width, get_dynamic_name (filedata, psym->st_name));
+ else
+ printf (_("<corrupt: %14ld>"), psym->st_name);
+ }
+ }
+
+ ent = next_ent;
+ printf ("\n");
+ }
+ printf ("\n");
+
+ sgot_print_fail:
+ if (data)
+ free (data);
+
+ for (i = REL; i <= JMPREL; i++)
+ if (rtable[i].rels)
+ free (rtable[i].rels);
+
+ return (ent != (bfd_vma) -1);;
+}
+
+
+static bool
+process_nanomips_specific (Filedata * filedata)
+{
+ process_attributes (filedata, NULL, SHT_GNU_ATTRIBUTES, NULL,
+ display_nanomips_gnu_attribute);
+
+ /* Pretty-print the GOT. */
+ return print_nanomips_got (filedata);
+}
+
static bool
process_gnu_liblist (Filedata * filedata)
{
@@ -24759,6 +25178,9 @@ process_arch_specific (Filedata * filedata)
display_riscv_attribute,
display_generic_attribute);
+ case EM_NANOMIPS:
+ return process_nanomips_specific (filedata);
+
case EM_NDS32:
return process_nds32_specific (filedata);
--
2.39.5
More information about the Binutils
mailing list