[PATCH 4/6] Readelf for nanoMIPS.

"Tsing" <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
From: tsing <[email protected]>

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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.