aboutsummaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux
diff options
context:
space:
mode:
Diffstat (limited to 'libc/sysdeps/linux')
-rw-r--r--libc/sysdeps/linux/sh/Makefile.arch7
-rw-r--r--libc/sysdeps/linux/sh/bits/elf-fdpic.h115
-rw-r--r--libc/sysdeps/linux/sh/clone.S17
-rw-r--r--libc/sysdeps/linux/sh/crt1.S126
-rw-r--r--libc/sysdeps/linux/sh/crtreloc.c141
-rw-r--r--libc/sysdeps/linux/sh/setjmp.S12
-rw-r--r--libc/sysdeps/linux/sh/sys/ptrace.h176
-rw-r--r--libc/sysdeps/linux/sh/syscall_error.S18
8 files changed, 605 insertions, 7 deletions
diff --git a/libc/sysdeps/linux/sh/Makefile.arch b/libc/sysdeps/linux/sh/Makefile.arch
index 77ad570d6..e2e47bbdf 100644
--- a/libc/sysdeps/linux/sh/Makefile.arch
+++ b/libc/sysdeps/linux/sh/Makefile.arch
@@ -6,8 +6,13 @@
# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
#
+ifeq ($(UCLIBC_FORMAT_FDPIC_ELF),y)
+FDPIC_CSRC=crtreloc.c
+endif
+
CSRC := \
- mmap.c pipe.c __init_brk.c brk.c sbrk.c syscall.c pread_write.c
+ mmap.c pipe.c __init_brk.c brk.c sbrk.c syscall.c pread_write.c \
+ $(FDPIC_CSRC)
SSRC := setjmp.S __longjmp.S vfork.S clone.S ___fpscr_values.S
diff --git a/libc/sysdeps/linux/sh/bits/elf-fdpic.h b/libc/sysdeps/linux/sh/bits/elf-fdpic.h
new file mode 100644
index 000000000..6b957bdfe
--- /dev/null
+++ b/libc/sysdeps/linux/sh/bits/elf-fdpic.h
@@ -0,0 +1,115 @@
+/* Copyright 2003, 2004 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation; either version 2.1 of the
+License, or (at your option) any later version.
+
+In addition to the permissions in the GNU Lesser General Public
+License, the Free Software Foundation gives you unlimited
+permission to link the compiled version of this file with other
+programs, and to distribute those programs without any restriction
+coming from the use of this file. (The GNU Lesser General Public
+License restrictions do apply in other respects; for example, they
+cover modification of the file, and distribution when not linked
+into another program.)
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifndef _BITS_ELF_FDPIC_H
+#define _BITS_ELF_FDPIC_H
+
+/* These data structures are described in the FDPIC ABI extension.
+ The kernel passes a process a memory map, such that for every LOAD
+ segment there is an elf32_fdpic_loadseg entry. A pointer to an
+ elf32_fdpic_loadmap is passed in R8 at start-up, and a pointer to
+ an additional such map is passed in R9 for the interpreter, when
+ there is one. */
+
+#include <elf.h>
+
+/* This data structure represents a PT_LOAD segment. */
+struct elf32_fdpic_loadseg
+{
+ /* Core address to which the segment is mapped. */
+ Elf32_Addr addr;
+ /* VMA recorded in the program header. */
+ Elf32_Addr p_vaddr;
+ /* Size of this segment in memory. */
+ Elf32_Word p_memsz;
+};
+
+struct elf32_fdpic_loadmap {
+ /* Protocol version number, must be zero. */
+ Elf32_Half version;
+ /* Number of segments in this map. */
+ Elf32_Half nsegs;
+ /* The actual memory map. */
+ struct elf32_fdpic_loadseg segs[/*nsegs*/];
+};
+
+struct elf32_fdpic_loadaddr {
+ struct elf32_fdpic_loadmap *map;
+ void *got_value;
+};
+
+/* Map a pointer's VMA to its corresponding address according to the
+ load map. */
+static __always_inline void *
+__reloc_pointer (void *p,
+ const struct elf32_fdpic_loadmap *map)
+{
+ int c;
+
+#if 0
+ if (map->version != 0)
+ /* Crash. */
+ ((void(*)())0)();
+#endif
+
+ /* No special provision is made for NULL. We don't want NULL
+ addresses to go through relocation, so they shouldn't be in
+ .rofixup sections, and, if they're present in dynamic
+ relocations, they shall be mapped to the NULL address without
+ undergoing relocations. */
+
+ for (c = 0;
+ /* Take advantage of the fact that the loadmap is ordered by
+ virtual addresses. In general there will only be 2 entries,
+ so it's not profitable to do a binary search. */
+ c < map->nsegs && p >= (void*)map->segs[c].p_vaddr;
+ c++)
+ {
+ /* This should be computed as part of the pointer comparison
+ above, but we want to use the carry in the comparison, so we
+ can't convert it to an integer type beforehand. */
+ unsigned long offset = p - (void*)map->segs[c].p_vaddr;
+ /* We only check for one-past-the-end for the last segment,
+ assumed to be the data segment, because other cases are
+ ambiguous in the absence of padding between segments, and
+ rofixup already serves as padding between text and data.
+ Unfortunately, unless we special-case the last segment, we
+ fail to relocate the _end symbol. */
+ if (offset < map->segs[c].p_memsz
+ || (offset == map->segs[c].p_memsz && c + 1 == map->nsegs))
+ return (char*)map->segs[c].addr + offset;
+ }
+
+ /* We might want to crash instead. */
+ return (void*)-1;
+}
+
+# define __RELOC_POINTER(ptr, loadaddr) \
+ (__reloc_pointer ((void*)(ptr), \
+ (loadaddr).map))
+
+#endif /* _BITS_ELF_FDPIC_H */
diff --git a/libc/sysdeps/linux/sh/clone.S b/libc/sysdeps/linux/sh/clone.S
index b912db0ad..b0b5fcdbe 100644
--- a/libc/sysdeps/linux/sh/clone.S
+++ b/libc/sysdeps/linux/sh/clone.S
@@ -26,7 +26,9 @@
#include <bits/sysnum.h>
-#ifdef __HAVE_SHARED__
+#ifdef __SH_FDPIC__
+#define PLTJMP(_x) _x@PLT-.
+#elif defined __HAVE_SHARED__
#define PLTJMP(_x) _x@PLT
#else
#define PLTJMP(_x) _x
@@ -94,12 +96,23 @@ clone:
3:
/* thread starts */
mov.l @r15, r1
+#ifdef __SH_FDPIC__
+ /* r1 contains a function descriptor. */
+ mov.l @(4,r1), r12
+ mov.l @r1, r1
+#endif
jsr @r1
mov.l @(4,r15), r4
/* we are done, passing the return value through r0 */
mov.l .L1, r1
-#ifdef __HAVE_SHARED__
+#ifdef __SH_FDPIC__
+ mov r0, r4
+ mov.l .L1, r0
+ add r0, r1
+ jmp @r1
+ nop
+#elif defined __HAVE_SHARED__
mov.l r12, @-r15
sts.l pr, @-r15
mov r0, r4
diff --git a/libc/sysdeps/linux/sh/crt1.S b/libc/sysdeps/linux/sh/crt1.S
index 9707f8316..717b0f867 100644
--- a/libc/sysdeps/linux/sh/crt1.S
+++ b/libc/sysdeps/linux/sh/crt1.S
@@ -28,6 +28,7 @@
This is how the dynamic linker arranges to have DT_FINI
functions called for shared libraries that have been loaded
before this code runs.
+ For FDPIC, this will be a function descriptor.
sp The stack contains the arguments and environment:
0(sp) argc
@@ -37,6 +38,12 @@
(4*(argc+1))(sp) envp[0]
...
NULL
+
+ FDPIC only:
+
+ r8 Contains the address of the load map.
+ The type is "const struct elf32_fdpic_loadmap *".
+ See sh/bits/elf-fdpic.h.
*/
#include <features.h>
@@ -49,6 +56,89 @@ _start:
/* Clear the frame pointer since this is the outermost frame. */
mov #0, r14
+#ifdef __ARCH_HAS_NO_MMU__
+ /* ucLinux doesn't seem to provide a valid loader finalization
+ function pointer. */
+ mov #0, r4
+#endif
+
+#ifdef __SH_FDPIC__
+ mov r4, r10 /* move to callee save */
+
+ /* GOT = __self_reloc (load_map, rofixup, rofixupend) */
+ mov r8, r4
+ mova L_rofixup, r0
+ mov.l L_rofixup, r5
+ add r0, r5
+ mova L_rofixupend, r0
+ mov.l L_rofixupend, r6
+ add r0, r6
+
+ mova L_self_reloc, r0
+ mov.l L_self_reloc, r1
+ add r0, r1
+ jsr @r1
+ nop
+ mov r0, r12
+ /* r12 now contains the GOT/FDPIC address. */
+
+#ifdef __SH2A_DOUBLE__
+ /* The SH2A kernel doesn't initialize the FPSCR to double precision. */
+ mov r12, r13
+
+#ifdef __FMOVD_ENABLED__
+ movi20s #0x180000, r4
+#else
+ movi20s #0x80000, r4
+#endif
+ mov.l L_set_fpscr, r0
+ mov.l @(r0,r12), r1
+ mov.l @(0,r1), r0
+ jsr @r0
+ mov.l @(4,r1), r12
+
+ mov r13, r12
+#endif
+
+ /* Pop argc off the stack and save a pointer to argv */
+ mov.l @r15+,r5
+ mov r15, r6
+
+ /* In FDPIC, the GOT register is caller save. */
+ mov.l r12, @-r15
+
+ /* Push the stack_end, rtld_fini and fini func onto the stack */
+ mov.l r6,@-r15
+ mov.l r10,@-r15
+ mov.l L_fini,r0
+ add r12, r0
+ mov.l r0,@-r15
+
+ /* Set up the main/init funcs that go in registers */
+ mov.l L_main, r4
+ add r12, r4
+ mov.l L_init, r7
+ add r12, r7
+
+ /* __uClibc_main (main, argc, argv, init, fini, rtld_fini, stack_end) */
+
+ /* Let the libc call main and exit with its return code. */
+ mov.l L_uClibc_main,r0
+ mov.l @(r0,r12), r0
+ mov.l @(0,r0),r1
+ jsr @r1
+ mov.l @(4,r0), r12
+
+ /* We should not get here. */
+ add #12, r15 /* Pop parameters from stack. */
+ mov.l @r15+, r12
+ mov.l L_abort,r0
+ mov.l @(r0,r12), r0
+ mov.l @(0,r0),r1
+ jsr @r1
+ mov.l @(4,r0), r12
+
+#elif defined __PIC__
/* Pop argc off the stack and save a pointer to argv */
mov.l @r15+,r5
mov r15, r6
@@ -57,7 +147,6 @@ _start:
mov.l r6,@-r15
mov.l r4,@-r15
-#ifdef __PIC__
mova L_got, r0
mov.l L_got, r12
add r0, r12
@@ -85,6 +174,14 @@ _start:
jsr @r1
nop
#else
+ /* Pop argc off the stack and save a pointer to argv */
+ mov.l @r15+,r5
+ mov r15, r6
+
+ /* Push the stack_end, rtld_fini and fini func onto the stack */
+ mov.l r6,@-r15
+ mov.l r4,@-r15
+
mov.l L_fini,r0
mov.l r0,@-r15
@@ -107,7 +204,32 @@ _start:
.size _start,.-_start
.align 2
-#ifdef __PIC__
+#ifdef __SH_FDPIC__
+/* These are used before the FDPIC register is set, so must be relative.
+ The functions must be implemented without using r12. */
+L_self_reloc:
+ .long __self_reloc@PCREL
+L_rofixup:
+ .long __ROFIXUP_LIST__@PCREL
+L_rofixupend:
+ .long __ROFIXUP_END__@PCREL
+
+/* These must use FDPIC relocations. */
+#ifdef __SH2A_DOUBLE__
+L_set_fpscr:
+ .long __set_fpscr@GOTFUNCDESC
+#endif
+L_main:
+ .long main@GOTOFFFUNCDESC
+L_init:
+ .long _init@GOTOFFFUNCDESC
+L_fini:
+ .long _fini@GOTOFFFUNCDESC
+L_uClibc_main:
+ .long __uClibc_main@GOTFUNCDESC
+L_abort:
+ .long abort@GOTFUNCDESC
+#elif defined __PIC__
L_got:
.long _GLOBAL_OFFSET_TABLE_
L_main:
diff --git a/libc/sysdeps/linux/sh/crtreloc.c b/libc/sysdeps/linux/sh/crtreloc.c
new file mode 100644
index 000000000..01fde6fc3
--- /dev/null
+++ b/libc/sysdeps/linux/sh/crtreloc.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ written by Alexandre Oliva <aoliva@redhat.com>
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation; either version 2.1 of the
+License, or (at your option) any later version.
+
+In addition to the permissions in the GNU Lesser General Public
+License, the Free Software Foundation gives you unlimited
+permission to link the compiled version of this file with other
+programs, and to distribute those programs without any restriction
+coming from the use of this file. (The GNU Lesser General Public
+License restrictions do apply in other respects; for example, they
+cover modification of the file, and distribution when not linked
+into another program.)
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include <link.h>
+
+#ifdef __LITTLE_ENDIAN__
+#define BYTE(n) (n)
+#else
+#define BYTE(n) (3-(n))
+#endif
+
+/* This file is to be compiled into crt object files, to enable
+ executables to easily self-relocate. */
+
+static __always_inline int
+unaligned_read (int *src)
+{
+ unsigned char *bytes = (unsigned char *)src;
+
+ return (bytes[BYTE(0)]
+ | (bytes[BYTE(1)] << 8)
+ | (bytes[BYTE(2)] << 16)
+ | (bytes[BYTE(3)] << 24));
+}
+
+static __always_inline void
+unaligned_write (int *dest, int val)
+{
+ char *bytes = (char *)dest;
+
+ bytes[BYTE(0)] = val & 0xff;
+ bytes[BYTE(1)] = (val >> 8) & 0xff;
+ bytes[BYTE(2)] = (val >> 16) & 0xff;
+ bytes[BYTE(3)] = (val >> 24) & 0xff;
+}
+
+/* Compute the runtime address of pointer in the range [p,e), and then
+ map the pointer pointed by it. */
+static __always_inline void ***
+reloc_range_indirect (void ***p, void ***e,
+ const struct elf32_fdpic_loadmap *map)
+{
+ while (p < e)
+ {
+ void *ptr = __reloc_pointer (*p, map);
+ if (ptr)
+ {
+ void *pt = (void *)unaligned_read (ptr);
+ pt = __reloc_pointer (pt, map);
+ unaligned_write (ptr, (int)pt);
+ }
+ p++;
+ }
+ return p;
+}
+
+/* Call __reloc_range_indirect for the given range except for the last
+ entry, whose contents are only relocated. It's expected to hold
+ the GOT value. */
+void* attribute_hidden
+__self_reloc (const struct elf32_fdpic_loadmap *map,
+ void ***p, void ***e)
+{
+ p = reloc_range_indirect (p, e-1, map);
+
+ if (p >= e)
+ return (void*)-1;
+
+ return __reloc_pointer (*p, map);
+}
+
+#if 0
+/* These are other functions that might be useful, but that we don't
+ need. */
+
+/* Remap pointers in [p,e). */
+static __always_inline void**
+reloc_range (void **p, void **e,
+ const struct elf32_fdpic_loadmap *map)
+{
+ while (p < e)
+ {
+ *p = __reloc_pointer (*p, map);
+ p++;
+ }
+ return p;
+}
+
+/* Remap p, adjust e by the same offset, then map the pointers in the
+ range determined by them. */
+void attribute_hidden
+__reloc_range (const struct elf32_fdpic_loadmap *map,
+ void **p, void **e)
+{
+ void **old = p;
+
+ p = __reloc_pointer (p, map);
+ e += p - old;
+ reloc_range (p, e, map);
+}
+
+/* Remap p, adjust e by the same offset, then map pointers referenced
+ by the (unadjusted) pointers in the range. Return the relocated
+ value of the last pointer in the range. */
+void* attribute_hidden
+__reloc_range_indirect (const struct elf32_fdpic_loadmap *map,
+ void ***p, void ***e)
+{
+ void ***old = p;
+
+ p = __reloc_pointer (p, map);
+ e += p - old;
+ return reloc_range_indirect (p, e, map);
+}
+#endif
diff --git a/libc/sysdeps/linux/sh/setjmp.S b/libc/sysdeps/linux/sh/setjmp.S
index 3296c2ba9..73a2a8b58 100644
--- a/libc/sysdeps/linux/sh/setjmp.S
+++ b/libc/sysdeps/linux/sh/setjmp.S
@@ -77,7 +77,17 @@ __sigsetjmp_intern:
mov.l r9, @-r4
mov.l r8, @-r4
-#ifdef __HAVE_SHARED__
+#ifdef __SH_FDPIC__
+ /* Make a tail call to __sigjmp_save; it takes the same args. */
+ mov.l .L1, r0
+ mov.l @(r0,r12), r0
+ mov.l @(0,r0), r2
+ mov.l @(4,r0), r12
+ jmp @r2
+ mov r1, r0
+ .align 2
+.L1: .long __sigjmp_save@GOTFUNCDESC
+#elif defined __HAVE_SHARED__
mov.l .LG, r2
mova .LG, r0
add r0, r2
diff --git a/libc/sysdeps/linux/sh/sys/ptrace.h b/libc/sysdeps/linux/sh/sys/ptrace.h
new file mode 100644
index 000000000..49d358a74
--- /dev/null
+++ b/libc/sysdeps/linux/sh/sys/ptrace.h
@@ -0,0 +1,176 @@
+/* `ptrace' debugger support interface. Linux version.
+ Copyright (C) 1996-1999,2000,2006,2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYS_PTRACE_H
+#define _SYS_PTRACE_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+/* Type of the REQUEST argument to `ptrace.' */
+enum __ptrace_request
+{
+ /* Indicate that the process making this request should be traced.
+ All signals received by this process can be intercepted by its
+ parent, and its parent can use the other `ptrace' requests. */
+ PTRACE_TRACEME = 0,
+#define PT_TRACE_ME PTRACE_TRACEME
+
+ /* Return the word in the process's text space at address ADDR. */
+ PTRACE_PEEKTEXT = 1,
+#define PT_READ_I PTRACE_PEEKTEXT
+
+ /* Return the word in the process's data space at address ADDR. */
+ PTRACE_PEEKDATA = 2,
+#define PT_READ_D PTRACE_PEEKDATA
+
+ /* Return the word in the process's user area at offset ADDR. */
+ PTRACE_PEEKUSER = 3,
+#define PT_READ_U PTRACE_PEEKUSER
+
+ /* Write the word DATA into the process's text space at address ADDR. */
+ PTRACE_POKETEXT = 4,
+#define PT_WRITE_I PTRACE_POKETEXT
+
+ /* Write the word DATA into the process's data space at address ADDR. */
+ PTRACE_POKEDATA = 5,
+#define PT_WRITE_D PTRACE_POKEDATA
+
+ /* Write the word DATA into the process's user area at offset ADDR. */
+ PTRACE_POKEUSER = 6,
+#define PT_WRITE_U PTRACE_POKEUSER
+
+ /* Continue the process. */
+ PTRACE_CONT = 7,
+#define PT_CONTINUE PTRACE_CONT
+
+ /* Kill the process. */
+ PTRACE_KILL = 8,
+#define PT_KILL PTRACE_KILL
+
+ /* Single step the process.
+ This is not supported on all machines. */
+ PTRACE_SINGLESTEP = 9,
+#define PT_STEP PTRACE_SINGLESTEP
+
+ /* Get all general purpose registers used by a processes.
+ This is not supported on all machines. */
+ PTRACE_GETREGS = 12,
+#define PT_GETREGS PTRACE_GETREGS
+
+ /* Set all general purpose registers used by a processes.
+ This is not supported on all machines. */
+ PTRACE_SETREGS = 13,
+#define PT_SETREGS PTRACE_SETREGS
+
+ /* Get all floating point registers used by a processes.
+ This is not supported on all machines. */
+ PTRACE_GETFPREGS = 14,
+#define PT_GETFPREGS PTRACE_GETFPREGS
+
+ /* Set all floating point registers used by a processes.
+ This is not supported on all machines. */
+ PTRACE_SETFPREGS = 15,
+#define PT_SETFPREGS PTRACE_SETFPREGS
+
+ /* Attach to a process that is already running. */
+ PTRACE_ATTACH = 16,
+#define PT_ATTACH PTRACE_ATTACH
+
+ /* Detach from a process attached to with PTRACE_ATTACH. */
+ PTRACE_DETACH = 17,
+#define PT_DETACH PTRACE_DETACH
+
+ /* Get all extended floating point registers used by a processes.
+ This is not supported on all machines. */
+ PTRACE_GETFPXREGS = 18,
+#define PT_GETFPXREGS PTRACE_GETFPXREGS
+
+ /* Set all extended floating point registers used by a processes.
+ This is not supported on all machines. */
+ PTRACE_SETFPXREGS = 19,
+#define PT_SETFPXREGS PTRACE_SETFPXREGS
+
+ /* Continue and stop at the next (return from) syscall. */
+ PTRACE_SYSCALL = 24,
+#define PT_SYSCALL PTRACE_SYSCALL
+
+ /* Obtain the load map of the main program or the interpreter of the
+ ptraced process, depending on whether the addr argument is
+ (void*)0 or (void*)1, respectively. */
+ PTRACE_GETFDPIC = 31,
+#define PT_GETFDPIC PTRACE_GETFDPIC
+
+ /* Set ptrace filter options. */
+ PTRACE_SETOPTIONS = 0x4200,
+#define PT_SETOPTIONS PTRACE_SETOPTIONS
+
+ /* Get last ptrace message. */
+ PTRACE_GETEVENTMSG = 0x4201,
+#define PT_GETEVENTMSG PTRACE_GETEVENTMSG
+
+ /* Get siginfo for process. */
+ PTRACE_GETSIGINFO = 0x4202,
+#define PT_GETSIGINFO PTRACE_GETSIGINFO
+
+ /* Set new siginfo for process. */
+ PTRACE_SETSIGINFO = 0x4203
+#define PT_SETSIGINFO PTRACE_SETSIGINFO
+};
+
+#define PTRACE_GETFDPIC_EXEC ((void*)0) /* [addr] request the executable loadmap */
+#define PTRACE_GETFDPIC_INTERP ((void*)1) /* [addr] request the interpreter loadmap */
+
+/* Options set using PTRACE_SETOPTIONS. */
+enum __ptrace_setoptions {
+ PTRACE_O_TRACESYSGOOD = 0x00000001,
+ PTRACE_O_TRACEFORK = 0x00000002,
+ PTRACE_O_TRACEVFORK = 0x00000004,
+ PTRACE_O_TRACECLONE = 0x00000008,
+ PTRACE_O_TRACEEXEC = 0x00000010,
+ PTRACE_O_TRACEVFORKDONE = 0x00000020,
+ PTRACE_O_TRACEEXIT = 0x00000040,
+ PTRACE_O_MASK = 0x0000007f
+};
+
+/* Wait extended result codes for the above trace options. */
+enum __ptrace_eventcodes {
+ PTRACE_EVENT_FORK = 1,
+ PTRACE_EVENT_VFORK = 2,
+ PTRACE_EVENT_CLONE = 3,
+ PTRACE_EVENT_EXEC = 4,
+ PTRACE_EVENT_VFORK_DONE = 5,
+ PTRACE_EVENT_EXIT = 6
+};
+
+/* Perform process tracing functions. REQUEST is one of the values
+ above, and determines the action to be taken.
+ For all requests except PTRACE_TRACEME, PID specifies the process to be
+ traced.
+
+ PID and the other arguments described above for the various requests should
+ appear (those that are used for the particular request) as:
+ pid_t PID, void *ADDR, int DATA, void *ADDR2
+ after REQUEST. */
+extern long int ptrace (enum __ptrace_request __request, ...) __THROW;
+
+__END_DECLS
+
+#endif /* _SYS_PTRACE_H */
diff --git a/libc/sysdeps/linux/sh/syscall_error.S b/libc/sysdeps/linux/sh/syscall_error.S
index 1764ebfc8..07f1cfb63 100644
--- a/libc/sysdeps/linux/sh/syscall_error.S
+++ b/libc/sysdeps/linux/sh/syscall_error.S
@@ -1,6 +1,19 @@
.align 4
__syscall_error:
/* Call errno_location, store '-r4' in errno and return -1 */
+#ifdef __SH_FDPIC__
+ neg r4, r4
+ sts.l pr, @-r15
+ mov.l r4, @-r15
+ mov.l 1f, r0
+ mov.l @(r0,r12), r0
+ mov.l @(0,r0), r1
+ jsr @r1
+ mov.l @(4,r0), r12
+ mov.l @r15+, r4
+ lds.l @r15+, pr
+ mov.l r4, @r0
+#else
mov.l r12, @-r15
sts.l pr, @-r15
#ifdef __HAVE_SHARED__
@@ -20,6 +33,7 @@ __syscall_error:
mov.l r12, @r0
lds.l @r15+, pr
mov.l @r15+,r12
+#endif
/* And just kick back a -1. */
rts
@@ -27,7 +41,9 @@ __syscall_error:
.align 4
-#ifdef __HAVE_SHARED__
+#ifdef __SH_FDPIC__
+1: .long __errno_location@GOTFUNCDESC
+#elif defined __HAVE_SHARED__
1: .long __errno_location@GOT
.LG: .long _GLOBAL_OFFSET_TABLE_
#else