diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index d92c334f3a5..fa26810c198 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,14 @@
+2018-04-20  Alan Modra  <amodra@gmail.com>
+
+	PR 22978
+	* elf32-hppa.c (got_relocs_needed): Add extra param to special
+	case both dtprel and tprel relocs.
+	(allocate_dynrelocs): Adjust conditions for got relocs.
+	(elf32_hppa_relocate_section): Likewise for local sym got relocs.
+	Emit dynamic relocs on TLS GOT entries for shared libraries,
+	not when pic.  Omit dynamic reloc on dtprel entry when local,
+	and on tprel entry when local and executable.
+
 2018-04-19  Alan Modra  <amodra@gmail.com>
 
 	PR 22537
diff --git a/bfd/elf32-hppa.c b/bfd/elf32-hppa.c
index 44fb753c0ea..722452b5af7 100644
--- a/bfd/elf32-hppa.c
+++ b/bfd/elf32-hppa.c
@@ -1894,18 +1894,19 @@ got_entries_needed (int tls_type)
 }
 
 /* Calculate size of relocs needed for symbol given its TLS_TYPE and
-   NEEDed GOT entries.  KNOWN says a TPREL offset can be calculated
-   at link time.  */
+   NEEDed GOT entries.  TPREL_KNOWN says a TPREL offset can be
+   calculated at link time.  DTPREL_KNOWN says the same for a DTPREL
+   offset.  */
 
 static inline unsigned int
-got_relocs_needed (int tls_type, unsigned int need, bfd_boolean known)
+got_relocs_needed (int tls_type, unsigned int need,
+		   bfd_boolean dtprel_known, bfd_boolean tprel_known)
 {
   /* All the entries we allocated need relocs.
-     Except IE in executable with a local symbol.  We could also omit
-     the DTPOFF reloc on the second word of a GD entry under the same
-     condition as that for IE, but ld.so might want to differentiate
-     LD and GD entries at some stage.  */
-  if ((tls_type & GOT_TLS_IE) != 0 && known)
+     Except for GD and IE with local symbols.  */
+  if ((tls_type & GOT_TLS_GD) != 0 && dtprel_known)
+    need -= GOT_ENTRY_SIZE;
+  if ((tls_type & GOT_TLS_IE) != 0 && tprel_known)
     need -= GOT_ENTRY_SIZE;
   return need * sizeof (Elf32_External_Rela) / GOT_ENTRY_SIZE;
 }
@@ -1959,15 +1960,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *eh, void *inf)
       need = got_entries_needed (hh->tls_type);
       sec->size += need;
       if (htab->etab.dynamic_sections_created
-	  && (bfd_link_pic (info)
+	  && (bfd_link_dll (info)
+	      || (bfd_link_pic (info) && (hh->tls_type & GOT_NORMAL) != 0)
 	      || (eh->dynindx != -1
 		  && !SYMBOL_REFERENCES_LOCAL (info, eh)))
 	  && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh))
 	{
-	  bfd_boolean tprel_known = (bfd_link_executable (info)
-				     && SYMBOL_REFERENCES_LOCAL (info, eh));
+	  bfd_boolean local = SYMBOL_REFERENCES_LOCAL (info, eh);
 	  htab->etab.srelgot->size
-	    += got_relocs_needed (hh->tls_type, need, tprel_known);
+	    += got_relocs_needed (hh->tls_type, need, local,
+				  local && bfd_link_executable (info));
 	}
     }
   else
@@ -2192,12 +2194,12 @@ elf32_hppa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 	      *local_got = sec->size;
 	      need = got_entries_needed (*local_tls_type);
 	      sec->size += need;
-	      if (bfd_link_pic (info))
-		{
-		  bfd_boolean tprel_known = bfd_link_executable (info);
-		  htab->etab.srelgot->size
-		    += got_relocs_needed (*local_tls_type, need, tprel_known);
-		}
+	      if (bfd_link_dll (info)
+		  || (bfd_link_pic (info)
+		      && (*local_tls_type & GOT_NORMAL) != 0))
+		htab->etab.srelgot->size
+		  += got_relocs_needed (*local_tls_type, need, TRUE,
+					bfd_link_executable (info));
 	    }
 	  else
 	    *local_got = (bfd_vma) -1;
@@ -4041,7 +4043,7 @@ elf32_hppa_relocate_section (bfd *output_bfd,
 		   GD GOT are necessary, we emit the GD first.  */
 
 		if (indx != 0
-		    || (bfd_link_pic (info)
+		    || (bfd_link_dll (info)
 			&& (hh == NULL
 			    || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh))))
 		  {
@@ -4065,29 +4067,32 @@ elf32_hppa_relocate_section (bfd *output_bfd,
 			bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
 			htab->etab.srelgot->reloc_count++;
 			loc += sizeof (Elf32_External_Rela);
+			bfd_put_32 (output_bfd, 0,
+				    htab->etab.sgot->contents + cur_off);
+		      }
+		    else
+		      /* If we are not emitting relocations for a
+			 general dynamic reference, then we must be in a
+			 static link or an executable link with the
+			 symbol binding locally.  Mark it as belonging
+			 to module 1, the executable.  */
+		      bfd_put_32 (output_bfd, 1,
+				  htab->etab.sgot->contents + cur_off);
+
+		    if (indx != 0)
+		      {
 			outrel.r_info
 			  = ELF32_R_INFO (indx, R_PARISC_TLS_DTPOFF32);
 			outrel.r_offset += 4;
 			bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
 			htab->etab.srelgot->reloc_count++;
 			loc += sizeof (Elf32_External_Rela);
-			bfd_put_32 (output_bfd, 0,
-				    htab->etab.sgot->contents + cur_off);
 			bfd_put_32 (output_bfd, 0,
 				    htab->etab.sgot->contents + cur_off + 4);
 		      }
 		    else
-		      {
-			/* If we are not emitting relocations for a
-			   general dynamic reference, then we must be in a
-			   static link or an executable link with the
-			   symbol binding locally.  Mark it as belonging
-			   to module 1, the executable.  */
-			bfd_put_32 (output_bfd, 1,
-				    htab->etab.sgot->contents + cur_off);
-			bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
-				    htab->etab.sgot->contents + cur_off + 4);
-		      }
+		      bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
+				  htab->etab.sgot->contents + cur_off + 4);
 		    cur_off += 8;
 		  }