diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index 2ae3413..2f63b80 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -985,6 +985,25 @@ default_print_insn (bfd_vma memaddr, disassemble_info *info)
   return (*disassemble_fn) (memaddr, info);
 }
 
+/* Wrapper to gdbarch_skip_prologue, but doesn't throw exception.  Catch
+   exception thrown from gdbarch_skip_prologue, and return PC.  */
+
+CORE_ADDR
+gdbarch_skip_prologue_noexcept (gdbarch *gdbarch, CORE_ADDR pc) noexcept
+{
+  CORE_ADDR new_pc = pc;
+
+  TRY
+    {
+      new_pc = gdbarch_skip_prologue (gdbarch, new_pc);
+    }
+  CATCH (ex, RETURN_MASK_ALL)
+    {}
+  END_CATCH
+
+  return new_pc;
+}
+
 /* -Wmissing-prototypes */
 extern initialize_file_ftype _initialize_gdbarch_utils;
 
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index 2aa9159..11c4afc 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -268,4 +268,7 @@ extern void default_guess_tracepoint_registers (struct gdbarch *gdbarch,
 
 extern int default_print_insn (bfd_vma memaddr, disassemble_info *info);
 
+extern CORE_ADDR gdbarch_skip_prologue_noexcept (gdbarch *gdbarch,
+						 CORE_ADDR pc) noexcept;
+
 #endif
diff --git a/gdb/infrun.c b/gdb/infrun.c
index a68da6a..37ff015 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -66,6 +66,7 @@
 #include "common/enum-flags.h"
 #include "progspace-and-thread.h"
 #include "common/gdb_optional.h"
+#include "arch-utils.h"
 
 /* Prototypes for local functions */
 
@@ -7317,8 +7318,8 @@ handle_step_into_function (struct gdbarch *gdbarch,
 
   cust = find_pc_compunit_symtab (stop_pc);
   if (cust != NULL && compunit_language (cust) != language_asm)
-    ecs->stop_func_start = gdbarch_skip_prologue (gdbarch,
-						  ecs->stop_func_start);
+    ecs->stop_func_start
+      = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start);
 
   stop_func_sal = find_pc_line (ecs->stop_func_start, 0);
   /* Use the step_resume_break to step until the end of the prologue,
@@ -7396,8 +7397,8 @@ handle_step_into_function_backward (struct gdbarch *gdbarch,
 
   cust = find_pc_compunit_symtab (stop_pc);
   if (cust != NULL && compunit_language (cust) != language_asm)
-    ecs->stop_func_start = gdbarch_skip_prologue (gdbarch,
-						  ecs->stop_func_start);
+    ecs->stop_func_start
+      = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start);
 
   stop_func_sal = find_pc_line (stop_pc, 0);
 
diff --git a/gdb/symtab.c b/gdb/symtab.c
index d4e107a..ccf31cc 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -64,6 +64,7 @@
 #include "progspace-and-thread.h"
 #include "common/gdb_optional.h"
 #include "filename-seen-cache.h"
+#include "arch-utils.h"
 
 /* Forward declarations for local functions.  */
 
@@ -3627,7 +3628,7 @@ skip_prologue_sal (struct symtab_and_line *sal)
       if (gdbarch_skip_entrypoint_p (gdbarch))
         pc = gdbarch_skip_entrypoint (gdbarch, pc);
       if (skip)
-	pc = gdbarch_skip_prologue (gdbarch, pc);
+	pc = gdbarch_skip_prologue_noexcept (gdbarch, pc);
 
       /* For overlays, map pc back into its mapped VMA range.  */
       pc = overlay_mapped_address (pc, section);
diff --git a/gdb/testsuite/gdb.base/reread.exp b/gdb/testsuite/gdb.base/reread.exp
index cc0f577..74bd20e 100644
--- a/gdb/testsuite/gdb.base/reread.exp
+++ b/gdb/testsuite/gdb.base/reread.exp
@@ -15,6 +15,11 @@
 
 set prototypes 1
 
+# Build programs in PIE mode, to reproduce PR 21555.
+foreach_with_prefix opts {
+    { "" "" }
+    { "-fPIE" "ldflags=-pie" } } {
+
 # build the first test case
 
 set testfile1 "reread1"
@@ -22,7 +27,7 @@ set srcfile1 ${testfile1}.c
 # Cygwin needs $EXEEXT.
 set binfile1 [standard_output_file ${testfile1}$EXEEXT]
 
-if  { [gdb_compile "${srcdir}/${subdir}/${srcfile1}" "${binfile1}" executable {debug nowarnings}] != "" } {
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile1}" "${binfile1}" executable [list debug nowarnings additional_flags=[lindex $opts 0] [lindex $opts 1]]] != "" } {
     untested "failed to compile first testcase"
     return -1
 }
@@ -33,8 +38,8 @@ set testfile2 "reread2"
 set srcfile2 ${testfile2}.c
 set binfile2 [standard_output_file ${testfile2}$EXEEXT]
 
-if  { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable {debug nowarnings}] != ""
-      && [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable {debug nowarnings additional_flags=-DNO_SECTIONS}] != ""} {
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable [list debug nowarnings additional_flags=[lindex $opts 0] [lindex $opts 1]]] != ""
+      && [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable [list debug nowarnings "additional_flags=-DNO_SECTIONS [lindex $opts 0]" [lindex $opts 1]]] != ""} {
     untested "failed to compile second testcase"
     return -1
 }
@@ -120,6 +125,7 @@ if [is_remote target] {
     gdb_test "" "Breakpoint.* foo .* at .*:9.*" "second pass: run to foo() second time"
 }
 
+}
 # End of tests.
 
 return 0
