From f7c540994e73e430e73d220109e911dff5961f16 Mon Sep 17 00:00:00 2001
From: Mahesh Bodapati <mbodapat@xilinx.com>
Date: Tue, 8 Nov 2016 11:54:08 +0530
Subject: [PATCH 04/34] [LOCAL]: Fix relaxation of assembler resolved
 references,Fixup debug_loc sections after linker relaxation Adds a new
 reloctype R_MICROBLAZE_32_NONE, used for passing reloc info from the
 assembler to the linker when the linker manages to fully resolve a local
 symbol reference.

This is a workaround for design flaws in the assembler to
linker interface with regards to linker relaxation.

Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Signed-off-by: David Holsgrove <david.holsgrove@xilinx.com>

Conflicts:
	bfd/elf32-microblaze.c
	binutils/readelf.c
	include/elf/microblaze.h

Conflicts:
	binutils/readelf.c

Conflicts:
	bfd/elf32-microblaze.c
---
 bfd/bfd-in2.h              |   5 ++
 bfd/elf32-microblaze.c     | 126 ++++++++++++++++++++++++++++---------
 bfd/libbfd.h               |   1 +
 bfd/reloc.c                |   6 ++
 binutils/readelf.c         |   4 ++
 gas/config/tc-microblaze.c |   4 ++
 include/elf/microblaze.h   |   2 +
 7 files changed, 119 insertions(+), 29 deletions(-)

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 1f0f18a7e75..26e3bb2b34b 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5379,6 +5379,11 @@ value relative to the read-write small data area anchor  */
 expressions of the form "Symbol Op Symbol"  */
   BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM,
 
+/* This is a 32 bit reloc that stores the 32 bit pc relative
+value in two words (with an imm instruction).No relocation is 
+done here - only used for relaxing  */
+  BFD_RELOC_MICROBLAZE_32_NONE,
+
 /* This is a 64 bit reloc that stores the 32 bit pc relative
 value in two words (with an imm instruction).  No relocation is
 done here - only used for relaxing  */
diff --git a/bfd/elf32-microblaze.c b/bfd/elf32-microblaze.c
index 013c32a1e51..7cf1b6eab5b 100644
--- a/bfd/elf32-microblaze.c
+++ b/bfd/elf32-microblaze.c
@@ -175,6 +175,20 @@ static reloc_howto_type microblaze_elf_howto_raw[] =
 	  false),		/* PC relative offset?  */
 
    /* This reloc does nothing.	Used for relaxation.  */
+   HOWTO (R_MICROBLAZE_32_NONE,	/* Type.  */
+          0,			/* Rightshift.  */
+          2,			/* Size (0 = byte, 1 = short, 2 = long).  */
+          32,			/* Bitsize.  */
+          true,			/* PC_relative.  */
+          0,			/* Bitpos.  */
+          complain_overflow_bitfield,  /* Complain on overflow.  */
+          NULL,                  /* Special Function.  */
+          "R_MICROBLAZE_32_NONE",/* Name.  */
+          false,		/* Partial Inplace.  */
+          0,			/* Source Mask.  */
+          0,			/* Dest Mask.  */
+          false),		/* PC relative offset?  */
+
    HOWTO (R_MICROBLAZE_64_NONE,	/* Type.  */
 	  0,			/* Rightshift.  */
 	  0,			/* Size.  */
@@ -560,7 +574,10 @@ microblaze_elf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
     case BFD_RELOC_NONE:
       microblaze_reloc = R_MICROBLAZE_NONE;
       break;
-    case BFD_RELOC_MICROBLAZE_64_NONE:
+    case BFD_RELOC_MICROBLAZE_32_NONE:
+      microblaze_reloc = R_MICROBLAZE_32_NONE;
+      break;
+     case BFD_RELOC_MICROBLAZE_64_NONE:
       microblaze_reloc = R_MICROBLAZE_64_NONE;
       break;
     case BFD_RELOC_32:
@@ -1954,18 +1971,26 @@ microblaze_elf_relax_section (bfd *abfd,
 		}
 	      break;
 	    case R_MICROBLAZE_NONE:
+	    case R_MICROBLAZE_32_NONE:
 	      {
 		/* This was a PC-relative instruction that was
 		   completely resolved.  */
 		size_t sfix, efix;
+                unsigned int val;
 		bfd_vma target_address;
 		target_address = irel->r_addend + irel->r_offset;
 		sfix = calc_fixup (irel->r_offset, 0, sec);
 		efix = calc_fixup (target_address, 0, sec);
-		irel->r_addend -= (efix - sfix);
-		/* Should use HOWTO.  */
-		microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset,
-						   irel->r_addend);
+
+                /* Validate the in-band val.  */
+                val = bfd_get_32 (abfd, contents + irel->r_offset);
+                if (val != irel->r_addend && ELF32_R_TYPE (irel->r_info) == R_MICROBLAZE_32_NONE) {
+                    fprintf(stderr, "%d: CORRUPT relax reloc %x %lx\n", __LINE__, val, irel->r_addend);
+                }
+	        irel->r_addend -= (efix - sfix);
+	        /* Should use HOWTO.  */
+	        microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset,
+	                                           irel->r_addend);
 	      }
 	      break;
 	    case R_MICROBLAZE_64_NONE:
@@ -2009,30 +2034,73 @@ microblaze_elf_relax_section (bfd *abfd,
 	  irelscanend = irelocs + o->reloc_count;
 	  for (irelscan = irelocs; irelscan < irelscanend; irelscan++)
 	    {
-	      if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32)
-		{
-		  isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
+              if (1 && ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_NONE)
+                {
+                  unsigned int val;
+
+                  isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
+
+                  /* hax: We only do the following fixup for debug location lists.  */
+                  if (strcmp(".debug_loc", o->name))
+                    continue;
+
+                  /* This was a PC-relative instruction that was completely resolved.  */
+                  if (ocontents == NULL)
+                    {
+		      if (elf_section_data (o)->this_hdr.contents != NULL)
+		          ocontents = elf_section_data (o)->this_hdr.contents;
+		      else
+		        {
+		          /* We always cache the section contents.
+			     Perhaps, if info->keep_memory is FALSE, we
+			     should free them, if we are permitted to.  */
+
+		          if (o->rawsize == 0)
+			      o->rawsize = o->size;
+		          ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
+		          if (ocontents == NULL)
+			      goto error_return;
+		          if (!bfd_get_section_contents (abfd, o, ocontents,
+                                                         (file_ptr) 0,
+                                                         o->rawsize))
+                              goto error_return;
+		          elf_section_data (o)->this_hdr.contents = ocontents;
+		        }
+		    }
 
-		  /* Look at the reloc only if the value has been resolved.  */
-		  if (isym->st_shndx == shndx
-		      && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION))
-		    {
-		      if (ocontents == NULL)
-			{
-			  if (elf_section_data (o)->this_hdr.contents != NULL)
-			    ocontents = elf_section_data (o)->this_hdr.contents;
-			  else
-			    {
-			      /* We always cache the section contents.
-				 Perhaps, if info->keep_memory is FALSE, we
-				 should free them, if we are permitted to.  */
-			      if (o->rawsize == 0)
-				o->rawsize = o->size;
-			      ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
-			      if (ocontents == NULL)
-				goto error_return;
-			      if (!bfd_get_section_contents (abfd, o, ocontents,
-							     (file_ptr) 0,
+                  val = bfd_get_32 (abfd, ocontents + irelscan->r_offset);
+                  if (val != irelscan->r_addend) {
+			fprintf(stderr, "%d: CORRUPT relax reloc! %x %lx\n", __LINE__, val, irelscan->r_addend);
+                  }
+
+                  irelscan->r_addend -= calc_fixup (irelscan->r_addend, 0, sec);
+                  microblaze_bfd_write_imm_value_32 (abfd, ocontents + irelscan->r_offset,
+                                                     irelscan->r_addend);
+              }
+              if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32)
+                {
+	          isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
+
+                  /* Look at the reloc only if the value has been resolved.  */
+                  if (isym->st_shndx == shndx
+                      && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION))
+                    {
+                      if (ocontents == NULL)
+                        {
+                          if (elf_section_data (o)->this_hdr.contents != NULL)
+                            ocontents = elf_section_data (o)->this_hdr.contents;
+                          else
+                            {
+                              /* We always cache the section contents.
+                                 Perhaps, if info->keep_memory is FALSE, we
+                                 should free them, if we are permitted to.  */
+		              if (o->rawsize == 0)
+			        o->rawsize = o->size;
+                              ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
+                              if (ocontents == NULL)
+                                goto error_return;
+                              if (!bfd_get_section_contents (abfd, o, ocontents,
+                                                             (file_ptr) 0,
 							     o->rawsize))
 				goto error_return;
 			      elf_section_data (o)->this_hdr.contents = ocontents;
@@ -2068,7 +2136,7 @@ microblaze_elf_relax_section (bfd *abfd,
 			      elf_section_data (o)->this_hdr.contents = ocontents;
 			    }
 			}
-		      irelscan->r_addend -= calc_fixup (irel->r_addend
+		      irelscan->r_addend -= calc_fixup (irelscan->r_addend
 							+ isym->st_value,
 							0,
 							sec);
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 29e8187f95f..ea2507d1879 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2989,6 +2989,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_MICROBLAZE_32_ROSDA",
   "BFD_RELOC_MICROBLAZE_32_RWSDA",
   "BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM",
+  "BFD_RELOC_MICROBLAZE_32_NONE",
   "BFD_RELOC_MICROBLAZE_64_NONE",
   "BFD_RELOC_MICROBLAZE_64_GOTPC",
   "BFD_RELOC_MICROBLAZE_64_GOT",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 36999fe9a40..5ac8a8536a7 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6867,6 +6867,12 @@ ENUM
 ENUMDOC
   This is a 32 bit reloc for the microblaze to handle
   expressions of the form "Symbol Op Symbol"
+ENUM
+  BFD_RELOC_MICROBLAZE_32_NONE
+ENUMDOC
+  This is a 32 bit reloc that stores the 32 bit pc relative
+  value in two words (with an imm instruction).  No relocation is
+  done here - only used for relaxing
 ENUM
   BFD_RELOC_MICROBLAZE_64_NONE
 ENUMDOC
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 0f5977bc072..acd12713361 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -14621,6 +14621,10 @@ is_8bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
       return reloc_type == 1;  /* R_Z80_8.  */
     default:
       return false;
+    case EM_MICROBLAZE:
+      return reloc_type == 33 /* R_MICROBLAZE_32_NONE.  */
+             || reloc_type == 0 /* R_MICROBLAZE_NONE.  */
+             || reloc_type == 9; /* R_MICROBLAZE_64_NONE.  */
     }
 }
 
diff --git a/gas/config/tc-microblaze.c b/gas/config/tc-microblaze.c
index c927331ea0a..8018d1f5686 100644
--- a/gas/config/tc-microblaze.c
+++ b/gas/config/tc-microblaze.c
@@ -2211,9 +2211,12 @@ md_apply_fix (fixS *   fixP,
 	 moves code around due to relaxing.  */
       if (fixP->fx_r_type == BFD_RELOC_64_PCREL)
 	fixP->fx_r_type = BFD_RELOC_MICROBLAZE_64_NONE;
+      else if (fixP->fx_r_type == BFD_RELOC_32)
+	fixP->fx_r_type = BFD_RELOC_MICROBLAZE_32_NONE;
       else
 	fixP->fx_r_type = BFD_RELOC_NONE;
       fixP->fx_addsy = section_symbol (absolute_section);
+      fixP->fx_done = 0;
     }
   return;
 }
@@ -2434,6 +2437,7 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
   switch (fixp->fx_r_type)
     {
     case BFD_RELOC_NONE:
+    case BFD_RELOC_MICROBLAZE_32_NONE:
     case BFD_RELOC_MICROBLAZE_64_NONE:
     case BFD_RELOC_32:
     case BFD_RELOC_MICROBLAZE_32_LO:
diff --git a/include/elf/microblaze.h b/include/elf/microblaze.h
index 43ad3ad3904..a2e1ce4580f 100644
--- a/include/elf/microblaze.h
+++ b/include/elf/microblaze.h
@@ -61,6 +61,8 @@ START_RELOC_NUMBERS (elf_microblaze_reloc_type)
   RELOC_NUMBER (R_MICROBLAZE_TEXTPCREL_64, 30)  /* PC-relative TEXT offset.  */
   RELOC_NUMBER (R_MICROBLAZE_TEXTREL_64, 31)    /* TEXT Entry offset 64-bit.  */
   RELOC_NUMBER (R_MICROBLAZE_TEXTREL_32_LO, 32) /* TEXT Entry offset 32-bit.  */
+  RELOC_NUMBER (R_MICROBLAZE_32_NONE, 33)
+   
 END_RELOC_NUMBERS (R_MICROBLAZE_max)
 
 /* Global base address names.  */
-- 
2.37.1 (Apple Git-137.1)

