diff --git a/linux-user/signal.c b/linux-user/signal.c
index 2ea3e03..75643d7 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -2039,13 +2039,13 @@ struct sigframe_v1
 {
     struct target_sigcontext sc;
     abi_ulong extramask[TARGET_NSIG_WORDS-1];
-    abi_ulong retcode;
+    abi_ulong retcode[4];
 };
 
 struct sigframe_v2
 {
     struct target_ucontext_v2 uc;
-    abi_ulong retcode;
+    abi_ulong retcode[4];
 };
 
 struct rt_sigframe_v1
@@ -2054,14 +2054,14 @@ struct rt_sigframe_v1
     abi_ulong puc;
     struct target_siginfo info;
     struct target_ucontext_v1 uc;
-    abi_ulong retcode;
+    abi_ulong retcode[4];
 };
 
 struct rt_sigframe_v2
 {
     struct target_siginfo info;
     struct target_ucontext_v2 uc;
-    abi_ulong retcode;
+    abi_ulong retcode[4];
 };
 
 #define TARGET_CONFIG_CPU_32 1
@@ -2084,6 +2084,23 @@ static const abi_ulong retcodes[4] = {
 	SWI_SYS_RT_SIGRETURN,	SWI_THUMB_RT_SIGRETURN
 };
 
+#if defined(CONFIG_USE_FDPIC)
+/*
+ * Stub needed to make sure the FD register (r9) contains the right
+ * value.
+ */
+static const unsigned long sigreturn_fdpic_codes[3] = {
+    0xe59fc004, /* ldr r12, [pc, #4] to read function descriptor */
+    0xe59c9004, /* ldr r9, [r12, #4] to setup GOT */
+    0xe59cf000  /* ldr pc, [r12] to jump into restorer */
+};
+
+static const unsigned long sigreturn_fdpic_thumb_codes[3] = {
+    0xc008f8df, /* ldr r12, [pc, #8] to read function descriptor */
+    0x9004f8dc, /* ldr r9, [r12, #4] to setup GOT */
+    0xf000f8dc  /* ldr pc, [r12] to jump into restorer */
+};
+#endif
 
 static inline int valid_user_regs(CPUARMState *regs)
 {
@@ -2143,7 +2160,19 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
 {
     abi_ulong handler = ka->_sa_handler;
     abi_ulong retcode;
+
+#ifdef CONFIG_USE_FDPIC
+    int thumb;
+
+    if (env->is_fdpic) {
+        thumb = (((abi_ulong *)g2h(ka->_sa_handler))[0]) & 1;
+    } else {
+        thumb = handler & 1;
+    }
+#else
     int thumb = handler & 1;
+#endif
+
     uint32_t cpsr = cpsr_read(env);
 
     cpsr &= ~CPSR_IT;
@@ -2154,8 +2183,37 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
     }
 
     if (ka->sa_flags & TARGET_SA_RESTORER) {
+#ifdef CONFIG_USE_FDPIC
+        if (env->is_fdpic) {
+            /* For FDPIC we ensure that the restorer is called with a
+             * correct r9 value.  For that we need to write code on
+             * the stack that sets r9 and jumps back to restorer
+             * value.
+             */
+            if (thumb) {
+                __put_user(sigreturn_fdpic_thumb_codes[0], rc);
+                __put_user(sigreturn_fdpic_thumb_codes[1], rc + 1);
+                __put_user(sigreturn_fdpic_thumb_codes[2], rc + 2);
+                __put_user((abi_ulong)ka->sa_restorer, rc + 3);
+            } else {
+                __put_user(sigreturn_fdpic_codes[0], rc);
+                __put_user(sigreturn_fdpic_codes[1], rc + 1);
+                __put_user(sigreturn_fdpic_codes[2], rc + 2);
+                __put_user((abi_ulong)ka->sa_restorer, rc + 3);
+            }
+
+            retcode = rc_addr + thumb;
+        } else
+#endif
         retcode = ka->sa_restorer;
     } else {
+#ifdef CONFIG_USE_FDPIC
+        if (env->is_fdpic) {
+            qemu_log_mask(LOG_UNIMP,
+                          "arm: FDPIC signal return not implemented");
+            abort();
+        } else {
+#endif
         unsigned int idx = thumb;
 
         if (ka->sa_flags & TARGET_SA_SIGINFO) {
@@ -2165,12 +2223,29 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
         __put_user(retcodes[idx], rc);
 
         retcode = rc_addr + thumb;
+#ifdef CONFIG_USE_FDPIC
+        }
+#endif
     }
 
     env->regs[0] = usig;
+#ifdef CONFIG_USE_FDPIC
+    if (env->is_fdpic) {
+        env->regs[9] = ((abi_ulong *)g2h(ka->_sa_handler))[1];
+    }
+#endif
     env->regs[13] = frame_addr;
     env->regs[14] = retcode;
+#ifdef CONFIG_USE_FDPIC
+    if (env->is_fdpic) {
+        env->regs[15] = ((abi_ulong *)g2h(ka->_sa_handler))[0]
+            & (thumb ? ~1 : ~3);
+    } else {
+        env->regs[15] = handler & (thumb ? ~1 : ~3);
+    }
+#else
     env->regs[15] = handler & (thumb ? ~1 : ~3);
+#endif
     cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
 }
 
@@ -2264,7 +2339,7 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka,
         __put_user(set->sig[i], &frame->extramask[i - 1]);
     }
 
-    setup_return(regs, ka, &frame->retcode, frame_addr, usig,
+    setup_return(regs, ka, frame->retcode, frame_addr, usig,
                  frame_addr + offsetof(struct sigframe_v1, retcode));
 
     unlock_user_struct(frame, frame_addr, 1);
@@ -2286,7 +2361,7 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka,
 
     setup_sigframe_v2(&frame->uc, set, regs);
 
-    setup_return(regs, ka, &frame->retcode, frame_addr, usig,
+    setup_return(regs, ka, frame->retcode, frame_addr, usig,
                  frame_addr + offsetof(struct sigframe_v2, retcode));
 
     unlock_user_struct(frame, frame_addr, 1);
@@ -2341,7 +2416,7 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
     }
 
-    setup_return(env, ka, &frame->retcode, frame_addr, usig,
+    setup_return(env, ka, frame->retcode, frame_addr, usig,
                  frame_addr + offsetof(struct rt_sigframe_v1, retcode));
 
     env->regs[1] = info_addr;
@@ -2372,7 +2447,7 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
 
     setup_sigframe_v2(&frame->uc, set, env);
 
-    setup_return(env, ka, &frame->retcode, frame_addr, usig,
+    setup_return(env, ka, frame->retcode, frame_addr, usig,
                  frame_addr + offsetof(struct rt_sigframe_v2, retcode));
 
     env->regs[1] = info_addr;
