summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2004-02-18 08:04:51 +0000
committerEric Andersen <andersen@codepoet.org>2004-02-18 08:04:51 +0000
commitbaa67289df42b1b994092b8312148a6f9e172274 (patch)
tree9a6a60a10a0db9879671cd923e7307c993cfbd40
parent377c7157a8802c289c5560f1a2ecd1030d571e7d (diff)
Alexandre Oliva writes:
This patch adds code to uClibc to support a new ABI designed for the FR-V architecture, that enables text segments of executables and shared libraries to be shared by multiple processes on an OS such as uClinux, that can run on FR-V processors without an MMU. Patches for binutils and GCC have just been posted in the corresponding mailing lists. The binutils patch was approved, but there's one additional patch pending review, that I posted this week. An updated GCC patch will be posted to gcc-patches@gcc.gnu.org as soon as I complete testing (I used a known-good compiler to test the uClibc patch below). Since the existing dynamic loader code didn't support independent relocation of segments, it required changes that were somewhat extensive. I've added a number of new machine-specific macros to try to keep the platform and ABI-specific details outside the generic code. I hope this is not a problem.
-rw-r--r--Rules.mak14
-rw-r--r--extra/Configs/Config.frv32
-rw-r--r--extra/Configs/Config.frv.default140
-rw-r--r--extra/Configs/Config.in7
-rw-r--r--include/elf.h16
-rw-r--r--ldso/ldso/frv/dl-startup.h89
-rw-r--r--ldso/ldso/frv/dl-syscalls.h191
-rw-r--r--ldso/ldso/frv/dl-sysdep.h628
-rw-r--r--ldso/ldso/frv/elfinterp.c495
-rw-r--r--ldso/ldso/frv/resolve.S71
-rw-r--r--libc/sysdeps/linux/frv/Makefile89
-rw-r--r--libc/sysdeps/linux/frv/__init_brk.c25
-rw-r--r--libc/sysdeps/linux/frv/__longjmp.S75
-rw-r--r--libc/sysdeps/linux/frv/_mmap.c48
-rw-r--r--libc/sysdeps/linux/frv/bits/elf-fdpic.h104
-rw-r--r--libc/sysdeps/linux/frv/bits/endian.h7
-rw-r--r--libc/sysdeps/linux/frv/bits/fcntl.h156
-rw-r--r--libc/sysdeps/linux/frv/bits/kernel_stat.h57
-rw-r--r--libc/sysdeps/linux/frv/bits/kernel_types.h43
-rw-r--r--libc/sysdeps/linux/frv/bits/mman.h75
-rw-r--r--libc/sysdeps/linux/frv/bits/setjmp.h53
-rw-r--r--libc/sysdeps/linux/frv/bits/stackinfo.h28
-rw-r--r--libc/sysdeps/linux/frv/bits/syscalls.h129
-rw-r--r--libc/sysdeps/linux/frv/bits/wordsize.h19
-rw-r--r--libc/sysdeps/linux/frv/brk.c22
-rw-r--r--libc/sysdeps/linux/frv/clone.S83
-rw-r--r--libc/sysdeps/linux/frv/crt0.S110
-rw-r--r--libc/sysdeps/linux/frv/crti.S41
-rw-r--r--libc/sysdeps/linux/frv/crtn.S35
-rw-r--r--libc/sysdeps/linux/frv/crtreloc.c118
-rw-r--r--libc/sysdeps/linux/frv/dl-iterate-phdr.c43
-rw-r--r--libc/sysdeps/linux/frv/sbrk.c25
-rw-r--r--libc/sysdeps/linux/frv/setjmp.S95
-rw-r--r--libc/sysdeps/linux/frv/sys/procfs.h125
-rw-r--r--libc/sysdeps/linux/frv/sys/ptrace.h139
-rw-r--r--libc/sysdeps/linux/frv/sys/ucontext.h451
-rw-r--r--libc/sysdeps/linux/frv/sysdep.c27
-rw-r--r--libc/sysdeps/linux/frv/vfork.S44
-rw-r--r--libpthread/linuxthreads/sysdeps/frv/pt-machine.h48
39 files changed, 3996 insertions, 1 deletions
diff --git a/Rules.mak b/Rules.mak
index 15c593abc..6a1b235e4 100644
--- a/Rules.mak
+++ b/Rules.mak
@@ -170,6 +170,20 @@ ifeq ($(strip $(TARGET_ARCH)),cris)
PICFLAG=-fpic
endif
+ifeq ($(strip $(TARGET_ARCH)),frv)
+ CPU_LDFLAGS-$(CONFIG_FRV)+=-melf32frvfd
+ CPU_CFLAGS-$(CONFIG_FRV)+=-mfdpic
+ PICFLAG=-fPIC -DPIC
+ PIEFLAG=-fpie
+ # Using -pie causes the program to have an interpreter, which is
+ # forbidden, so we must make do with -shared. Unfortunately,
+ # -shared by itself would get us global function descriptors
+ # and calls through PLTs, dynamic resolution of symbols, etc,
+ # which would break as well, but -Bsymbolic comes to the rescue.
+ LDPIEFLAG=-shared -Bsymbolic
+ UCLIBC_LDSO=ld.so.1
+endif
+
# Use '-Os' optimization if available, else use -O2, allow Config to override
OPTIMIZATION+=$(call check_gcc,-Os,-O2)
# Use the gcc 3.4 -funit-at-a-time optimization when available
diff --git a/extra/Configs/Config.frv b/extra/Configs/Config.frv
new file mode 100644
index 000000000..1210ad92f
--- /dev/null
+++ b/extra/Configs/Config.frv
@@ -0,0 +1,32 @@
+#
+# For a description of the syntax of this configuration file,
+# see extra/config/Kconfig-language.txt
+#
+
+config HAVE_ELF
+ bool
+ select HAS_FPU
+ select ARCH_BIG_ENDIAN
+ select ARCH_HAS_NO_MMU
+ default y
+
+config TARGET_ARCH
+ string
+ default "frv"
+
+config ARCH_CFLAGS
+ string
+
+config ARCH_LDFLAGS
+ string
+
+config LIBGCC_CFLAGS
+ string
+
+config HAVE_DOT_HIDDEN
+ bool
+ default y
+
+config UCLIBC_COMPLETELY_PIC
+ bool
+ default y
diff --git a/extra/Configs/Config.frv.default b/extra/Configs/Config.frv.default
new file mode 100644
index 000000000..4fd945d6d
--- /dev/null
+++ b/extra/Configs/Config.frv.default
@@ -0,0 +1,140 @@
+#
+# Automatically generated make config: don't edit
+#
+# TARGET_alpha is not set
+# TARGET_arm is not set
+# TARGET_cris is not set
+# TARGET_e1 is not set
+TARGET_frv=y
+# TARGET_h8300 is not set
+# TARGET_i386 is not set
+# TARGET_i960 is not set
+# TARGET_m68k is not set
+# TARGET_microblaze is not set
+# TARGET_mips is not set
+# TARGET_powerpc is not set
+# TARGET_sh is not set
+# TARGET_sparc is not set
+# TARGET_v850 is not set
+
+#
+# Target Architecture Features and Options
+#
+HAVE_ELF=y
+TARGET_ARCH="frv"
+HAVE_DOT_HIDDEN=y
+UCLIBC_COMPLETELY_PIC=y
+# ARCH_LITTLE_ENDIAN is not set
+# ARCH_BIG_ENDIAN is not set
+ARCH_HAS_NO_MMU=y
+UCLIBC_HAS_FLOATS=y
+HAS_FPU=y
+DO_C99_MATH=y
+WARNINGS="-Wall"
+KERNEL_SOURCE="$(FRV_KERNEL_DIR)"
+UCLIBC_UCLINUX_BROKEN_MUNMAP=y
+EXCLUDE_BRK=y
+C_SYMBOL_PREFIX=""
+HAVE_DOT_CONFIG=y
+
+#
+# General Library Settings
+#
+# HAVE_NO_PIC is not set
+DOPIC=y
+# HAVE_NO_SHARED is not set
+HAVE_SHARED=y
+# ARCH_HAS_NO_LDSO is not set
+BUILD_UCLIBC_LDSO=y
+FORCE_SHAREABLE_TEXT_SEGMENTS=y
+UCLIBC_PIE_SUPPORT=y
+LDSO_LDD_SUPPORT=y
+UCLIBC_CTOR_DTOR=y
+# UCLIBC_PROPOLICE is not set
+# UCLIBC_PROFILING is not set
+# HAS_NO_THREADS is not set
+UCLIBC_HAS_THREADS=y
+PTHREADS_DEBUG_SUPPORT=y
+UCLIBC_HAS_LFS=y
+MALLOC=y
+# MALLOC_SIMPLE is not set
+# MALLOC_STANDARD is not set
+# MALLOC_GLIBC_COMPAT is not set
+# UCLIBC_DYNAMIC_ATEXIT is not set
+HAS_SHADOW=y
+UNIX98PTY_ONLY=y
+ASSUME_DEVPTS=y
+# UCLIBC_HAS_TM_EXTENSIONS is not set
+UCLIBC_HAS_TZ_CACHING=y
+UCLIBC_HAS_TZ_FILE=y
+UCLIBC_HAS_TZ_FILE_READ_MANY=y
+UCLIBC_TZ_FILE_PATH="/etc/TZ"
+
+#
+# Networking Support
+#
+UCLIBC_HAS_IPV6=y
+UCLIBC_HAS_RPC=y
+UCLIBC_HAS_FULL_RPC=y
+
+#
+# String and Stdio Support
+#
+UCLIBC_HAS_CTYPE_TABLES=y
+UCLIBC_HAS_CTYPE_SIGNED=y
+# UCLIBC_HAS_CTYPE_UNSAFE is not set
+UCLIBC_HAS_CTYPE_CHECKED=y
+# UCLIBC_HAS_CTYPE_ENFORCED is not set
+UCLIBC_HAS_WCHAR=y
+# UCLIBC_HAS_LOCALE is not set
+# UCLIBC_HAS_HEXADECIMAL_FLOATS is not set
+UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
+UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9
+# UCLIBC_HAS_SCANF_GLIBC_A_FLAG is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_NONE is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_256 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_512 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_2048 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_4096 is not set
+UCLIBC_HAS_STDIO_BUFSIZ_8192=y
+UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE=y
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4 is not set
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8 is not set
+UCLIBC_HAS_STDIO_GETC_MACRO=y
+UCLIBC_HAS_STDIO_PUTC_MACRO=y
+UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION=y
+# UCLIBC_HAS_FOPEN_LARGEFILE_MODE is not set
+# UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE is not set
+# UCLIBC_HAS_GLIBC_CUSTOM_STREAMS is not set
+# UCLIBC_HAS_PRINTF_M_SPEC is not set
+UCLIBC_HAS_ERRNO_MESSAGES=y
+UCLIBC_HAS_SYS_ERRLIST=y
+UCLIBC_HAS_SIGNUM_MESSAGES=y
+UCLIBC_HAS_SYS_SIGLIST=y
+UCLIBC_HAS_GNU_GETOPT=y
+
+#
+# Big and Tall
+#
+UCLIBC_HAS_REGEX=y
+# UCLIBC_HAS_WORDEXP is not set
+# UCLIBC_HAS_FTW is not set
+UCLIBC_HAS_GLOB=y
+
+#
+# Library Installation Options
+#
+SHARED_LIB_LOADER_PREFIX="/lib"
+RUNTIME_PREFIX="/"
+DEVEL_PREFIX="/usr/"
+
+#
+# uClibc development/debugging options
+#
+# DODEBUG is not set
+DOASSERTS=y
+SUPPORT_LD_DEBUG=y
+# SUPPORT_LD_DEBUG_EARLY is not set
+UCLIBC_MALLOC_DEBUGGING=y
+# UCLIBC_MJN3_ONLY is not set
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index 8ad0073c3..4f15ea021 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -23,6 +23,9 @@ config TARGET_cris
config TARGET_e1
bool "e1"
+config TARGET_frv
+ bool "frv"
+
config TARGET_h8300
bool "h8300"
@@ -74,6 +77,10 @@ if TARGET_e1
source "extra/Configs/Config.e1"
endif
+if TARGET_frv
+source "extra/Configs/Config.frv"
+endif
+
if TARGET_h8300
source "extra/Configs/Config.h8300"
endif
diff --git a/include/elf.h b/include/elf.h
index b4de42e0d..e2264bd6c 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1,5 +1,5 @@
/* This file defines standard ELF types, structures, and macros.
- Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1995-1999, 2000, 2001, 2002, 2003 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
@@ -254,6 +254,9 @@ typedef struct
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
chances of collision with official or non-GNU unofficial values. */
+/* Fujitsu FR-V. */
+#define EM_CYGNUS_FRV 0x5441
+
#define EM_ALPHA 0x9026
/* V850 backend magic number. Written in the absense of an ABI. */
@@ -1116,6 +1119,17 @@ typedef struct
/* Keep this the last entry. */
#define R_386_NUM 38
+/* FR-V specific definitions. */
+#define R_FRV_NONE 0 /* No reloc. */
+#define R_FRV_32 1 /* Direct 32 bit. */
+/* Canonical function descriptor address. */
+#define R_FRV_FUNCDESC 14
+/* Private function descriptor initialization. */
+#define R_FRV_FUNCDESC_VALUE 18
+
+#define EF_FRV_PIC 0x00000100
+#define EF_FRV_FDPIC 0x00008000
+
/* SUN SPARC specific definitions. */
/* Legal values for ST_TYPE subfield of st_info (symbol type). */
diff --git a/ldso/ldso/frv/dl-startup.h b/ldso/ldso/frv/dl-startup.h
new file mode 100644
index 000000000..017efc0ad
--- /dev/null
+++ b/ldso/ldso/frv/dl-startup.h
@@ -0,0 +1,89 @@
+ /* Copyright (C) 2003 Red Hat, Inc.
+ Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+This file is part of uClibc.
+
+uClibc 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.
+
+uClibc 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 uClibc; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+USA. */
+
+/* Any assembly language/system dependent hacks needed to setup
+ * boot1.c so it will work as expected and cope with whatever platform
+ * specific wierdness is needed for this architecture.
+
+ * We override the default _dl_boot function, and replace it with a
+ * bit of asm. Then call the real _dl_boot function, which is now
+ * named _dl_boot2. */
+
+/* At program start-up, gr16 contains a pointer to a
+ elf32_fdpic_loadmap that describes how the executable was loaded
+ into memory. gr17 contains a pointer to the interpreter (our!)
+ loadmap, if there is an interpreter, or 0 if we're being run as an
+ executable. gr18 holds a pointer to the interpreter's dynamic
+ section, if there is an interpreter, or to the executable's dynamic
+ section, otherwise. If the executable is not dynamic, gr18 is 0.
+
+ We rely on the fact that the linker adds a pointer to the
+ _GLOBAL_OFFSET_TABLE_ as the last ROFIXUP entry, and that
+ __self_reloc returns the relocated pointer to us, so that we can
+ use this value to initialize the PIC register. */
+
+asm("" \
+" .text\n" \
+" .global _dl_boot\n" \
+" .type _dl_boot,@function\n" \
+"_dl_boot:\n" \
+" call .Lcall\n" \
+".Lcall:\n" \
+" movsg lr, gr4\n" \
+" sethi.p #gprelhi(.Lcall), gr5\n"\
+" setlo #gprello(.Lcall), gr5\n"\
+" mov.p gr17, gr8\n" \
+" cmp gr17, gr0, icc0\n" \
+" sub.p gr4, gr5, gr4\n" \
+" ckeq icc0, cc4\n" \
+" cmov.p gr16, gr8, cc4, 1\n" \
+" sethi #gprelhi(__ROFIXUP_LIST__), gr9\n" \
+" sethi.p #gprelhi(__ROFIXUP_END__), gr10\n" \
+" setlo #gprello(__ROFIXUP_LIST__), gr9\n" \
+" setlo.p #gprello(__ROFIXUP_END__), gr10\n" \
+" add gr9, gr4, gr9\n" \
+" add.p gr10, gr4, gr10\n" \
+" call __self_reloc\n" \
+" mov.p gr8, gr15\n" \
+" mov gr16, gr9\n" \
+" mov.p gr17, gr10\n" \
+" mov gr18, gr11\n" \
+" addi.p sp, #4, gr13\n" \
+" addi sp, #-8, sp\n" \
+" mov.p sp, gr12\n" \
+" call _dl_boot2\n" \
+" ldd.p @(sp, gr0), gr14\n" \
+" addi sp, #8, sp\n" \
+" movgs gr0, lr\n" \
+" jmpl @(gr14, gr0)\n" \
+" .size _dl_boot,.-_dl_boot\n" \
+);
+
+#define _dl_boot _dl_boot2
+#define DL_BOOT(X) \
+static void __attribute__ ((used)) \
+_dl_boot (void *dl_boot_got_pointer, \
+ struct elf32_fdpic_loadmap *dl_boot_progmap, \
+ struct elf32_fdpic_loadmap *dl_boot_ldsomap, \
+ Elf32_Dyn *dl_boot_ldso_dyn_pointer, \
+ struct funcdesc_value *dl_main_funcdesc, \
+ X)
+
+struct elf32_fdpic_loadmap;
diff --git a/ldso/ldso/frv/dl-syscalls.h b/ldso/ldso/frv/dl-syscalls.h
new file mode 100644
index 000000000..bef4f1720
--- /dev/null
+++ b/ldso/ldso/frv/dl-syscalls.h
@@ -0,0 +1,191 @@
+/* Copyright (C) 2003 Red Hat, Inc.
+ Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+This file is part of uClibc.
+
+uClibc 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.
+
+uClibc 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 uClibc; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+USA. */
+
+/* Define the __set_errno macro as nothing so that INLINE_SYSCALL
+ * won't set errno, which is important since we make system calls
+ * before the errno symbol is dynamicly linked. */
+
+#define __set_errno(X) {(void)(X);}
+#include "sys/syscall.h"
+#include <sys/mman.h>
+
+/* The code below is extracted from libc/sysdeps/linux/frv/_mmap.c */
+
+#define __NR___syscall_mmap2 __NR_mmap2
+static inline _syscall6(__ptr_t, __syscall_mmap2, __ptr_t, addr,
+ size_t, len, int, prot, int, flags, int, fd, off_t, offset);
+
+/* This is always 12, even on architectures where PAGE_SHIFT != 12. */
+# ifndef MMAP2_PAGE_SHIFT
+# define MMAP2_PAGE_SHIFT 12
+# endif
+
+#if DYNAMIC_LOADER_IN_SIMULATOR
+#include <asm/page.h> /* for PAGE_SIZE */
+inline static void *_dl_memset(void*,int,size_t);
+inline static ssize_t _dl_pread(int fd, void *buf, size_t count, off_t offset);
+#endif
+
+#ifndef DYNAMIC_LOADER_IN_SIMULATOR
+inline
+#endif
+static __ptr_t
+_dl_mmap(__ptr_t addr, size_t len, int prot, int flags, int fd, __off_t offset)
+{
+#ifdef DYNAMIC_LOADER_IN_SIMULATOR
+ size_t plen = (len + PAGE_SIZE - 1) & -PAGE_SIZE;
+
+/* This is a hack to enable the dynamic loader to run within a
+ simulator that doesn't support mmap, with a number of very ugly
+ tricks. Also, it's not as useful as it sounds, since only dynamic
+ executables without DT_NEEDED dependencies can be run. AFAIK, they
+ can only be created with -pie. This trick suffices to enable the
+ dynamic loader to obtain a blank page that it maps early in the
+ bootstrap. */
+ if ((flags & MAP_FIXED) == 0)
+ {
+ void *_dl_mmap_base = 0;
+ __ptr_t *ret = 0;
+
+ if (! _dl_mmap_base)
+ {
+ void *stack;
+ asm ("mov sp, %0" : "=r" (stack));
+ _dl_mmap_base = (void *)(((long)stack + 2 * PAGE_SIZE) & -PAGE_SIZE);
+ retry:
+ if (((void **)_dl_mmap_base)[0] == _dl_mmap_base
+ && ((void **)_dl_mmap_base)[1023] == _dl_mmap_base
+ && (((void **)_dl_mmap_base)[177]
+ == ((void **)_dl_mmap_base)[771]))
+ {
+ while (((void**)_dl_mmap_base)[177])
+ {
+ _dl_mmap_base = ((void**)_dl_mmap_base)[177];
+ if (!(((void **)_dl_mmap_base)[0] == _dl_mmap_base
+ && ((void **)_dl_mmap_base)[1023] == _dl_mmap_base
+ && (((void **)_dl_mmap_base)[177]
+ == ((void**)_dl_mmap_base)[771])))
+ ((void(*)())0)();
+ }
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < (int)PAGE_SIZE; i++)
+ if (*(char*)(_dl_mmap_base + i))
+ break;
+ if (i != PAGE_SIZE)
+ {
+ _dl_mmap_base = (void*)((long)_dl_mmap_base + PAGE_SIZE);
+ goto retry;
+ }
+ ((void**)_dl_mmap_base)[-1] =
+ ((void**)_dl_mmap_base)[0] =
+ ((void**)_dl_mmap_base)[1023] =
+ _dl_mmap_base;
+ }
+ }
+
+ if (_dl_mmap_base)
+ {
+ if (!(((void **)_dl_mmap_base)[0] == _dl_mmap_base
+ && ((void **)_dl_mmap_base)[1023] == _dl_mmap_base
+ && (((void **)_dl_mmap_base)[177]
+ == ((void**)_dl_mmap_base)[771])))
+ ((void(*)())0)();
+ ret = (__ptr_t)((char*)_dl_mmap_base + PAGE_SIZE);
+ _dl_mmap_base =
+ ((void**)_dl_mmap_base)[177] =
+ ((void**)_dl_mmap_base)[771] =
+ (char*)_dl_mmap_base + plen + PAGE_SIZE;
+ ((void**)_dl_mmap_base)[0] =
+ ((void**)_dl_mmap_base)[1023] =
+ _dl_mmap_base;
+ }
+
+ if ((flags & MAP_ANONYMOUS) != 0)
+ {
+ _dl_memset (ret, 0, plen);
+ return ret;
+ }
+
+ flags |= MAP_FIXED;
+ addr = ret;
+ }
+#endif
+ if (offset & ((1 << MMAP2_PAGE_SHIFT) - 1)) {
+#if 0
+ __set_errno (EINVAL);
+#endif
+ return MAP_FAILED;
+ }
+#ifdef DYNAMIC_LOADER_IN_SIMULATOR
+ if ((flags & MAP_FIXED) != 0)
+ {
+ if (_dl_pread(fd, addr, len, offset) != (ssize_t)len)
+ return (void*)MAP_FAILED;
+ if (plen != len)
+ _dl_memset (addr + len, 0, plen - len);
+ return addr;
+ }
+#endif
+ return(__syscall_mmap2(addr, len, prot, flags, fd, (off_t) (offset >> MMAP2_PAGE_SHIFT)));
+}
+
+#ifdef __NR_pread
+#ifdef DYNAMIC_LOADER_IN_SIMULATOR
+#include <unistd.h>
+
+#define __NR___syscall_lseek __NR_lseek
+inline static unsigned long _dl_read(int fd, const void *buf, unsigned long count);
+
+inline static _syscall3(__off_t, __syscall_lseek, int, fd, __off_t, offset,
+ int, whence);
+inline static ssize_t
+_dl_pread(int fd, void *buf, size_t count, off_t offset)
+{
+ __off_t orig = __syscall_lseek (fd, 0, SEEK_CUR);
+ ssize_t ret;
+
+ if (orig == -1)
+ return -1;
+
+ if (__syscall_lseek (fd, offset, SEEK_SET) != offset)
+ return -1;
+
+ ret = _dl_read (fd, buf, count);
+
+ if (__syscall_lseek (fd, orig, SEEK_SET) != orig)
+ ((void(*)())0)();
+
+ return ret;
+}
+#else
+#define __NR___syscall_pread __NR_pread
+inline static _syscall5(ssize_t, __syscall_pread, int, fd, void *, buf,
+ size_t, count, off_t, offset_hi, off_t, offset_lo);
+
+inline static ssize_t
+_dl_pread(int fd, void *buf, size_t count, off_t offset)
+{
+ return(__syscall_pread(fd,buf,count,__LONG_LONG_PAIR (offset >> 31, offset)));
+}
+#endif
+#endif
diff --git a/ldso/ldso/frv/dl-sysdep.h b/ldso/ldso/frv/dl-sysdep.h
new file mode 100644
index 000000000..ab3b09cd1
--- /dev/null
+++ b/ldso/ldso/frv/dl-sysdep.h
@@ -0,0 +1,628 @@
+ /* Copyright (C) 2003, 2004 Red Hat, Inc.
+ Contributed by Alexandre Oliva <aoliva@redhat.com>
+ Based on ../i386/dl-sysdep.h
+
+This file is part of uClibc.
+
+uClibc 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.
+
+uClibc 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 uClibc; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+USA. */
+
+/*
+ * Various assembly language/system dependent hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array. On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS)
+
+/*
+ * Compute the GOT address. On several platforms, we use assembly
+ * here. on FR-V FDPIC, there's no way to compute the GOT address,
+ * since the offset between text and data is not fixed, so we arrange
+ * for the assembly _dl_boot to pass this value as an argument to
+ * _dl_boot. */
+#define DL_BOOT_COMPUTE_GOT(got) ((got) = dl_boot_got_pointer)
+
+#define DL_BOOT_COMPUTE_DYN(dpnt, got, load_addr) \
+ ((dpnt) = dl_boot_ldso_dyn_pointer)
+
+/*
+ * Initialization sequence for a GOT. Copy the resolver function
+ * descriptor and the pointer to the elf_resolve/link_map data
+ * structure. Initialize the got_value in the module while at that.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{ \
+ (MODULE)->loadaddr.got_value = (GOT_BASE); \
+ GOT_BASE[0] = ((unsigned long *)&_dl_linux_resolve)[0]; \
+ GOT_BASE[1] = ((unsigned long *)&_dl_linux_resolve)[1]; \
+ GOT_BASE[2] = (unsigned long) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation. This is only used when
+ * bootstrapping the dynamic loader. RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB) \
+ switch(ELF32_R_TYPE((RELP)->r_info)){ \
+ case R_FRV_32: \
+ *(REL) += (SYMBOL); \
+ break; \
+ case R_FRV_FUNCDESC_VALUE: \
+ { \
+ struct funcdesc_value fv = { \
+ (void*)((SYMBOL) + *(REL)), \
+ (LOAD).got_value \
+ }; \
+ *(struct funcdesc_value volatile *)(REL) = fv; \
+ break; \
+ } \
+ default: \
+ _dl_exit(1); \
+ }
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done. We return the address of the function's entry point to
+ * _dl_boot, see boot1_arch.h.
+ */
+#define START() do { \
+ struct elf_resolve *exec_mod = _dl_loaded_modules; \
+ dl_main_funcdesc->entry_point = _dl_elf_main; \
+ while (exec_mod->libtype != elf_executable) \
+ exec_mod = exec_mod->next; \
+ dl_main_funcdesc->got_value = exec_mod->loadaddr.got_value; \
+ /* _dl_dprintf(2, "entry point is (%x,%x)\n", dl_main_funcdesc->entry_point, dl_main_funcdesc->got_value); */ \
+ return; \
+} while (0)
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_CYGNUS_FRV
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "FR-V"
+
+struct elf_resolve;
+
+struct funcdesc_value
+{
+ void *entry_point;
+ void *got_value;
+} __attribute__((__aligned__(8)));
+
+
+extern int _dl_linux_resolve(void) __attribute__((__visibility__("hidden")));
+
+#define do_rem(result, n, base) result = (n % base)
+
+/* 4096 bytes alignment */
+#define PAGE_ALIGN 0xfffff000
+#define ADDR_ALIGN 0xfff
+#define OFFS_ALIGN 0x7ffff000
+
+struct funcdesc_ht;
+
+/* We must force strings used early in the bootstrap into the data
+ segment, such that they are referenced with GOTOFF instead of
+ GPREL, because GPREL needs the GOT to have already been
+ relocated. */
+#define SEND_EARLY_STDERR(S) \
+ do { static char __s[] = (S); SEND_STDERR (__s); } while (0)
+
+#include <bits/elf-fdpic.h>
+#ifdef __USE_GNU
+# include <link.h>
+#else
+# define __USE_GNU
+# include <link.h>
+# undef __USE_GNU
+#endif
+#include <dl-syscall.h>
+#include <dl-string.h>
+
+/* These are declared in ldso.h, after it includes dl-elf.h that
+ includes ourselves. */
+extern void *_dl_malloc(int size);
+extern void _dl_free(void *);
+extern void _dl_dprintf(int, const char *, ...);
+
+
+#ifndef _dl_assert
+# define _dl_assert(expr)
+#endif
+
+/* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete
+ load map. */
+inline static void
+__dl_init_loadaddr_map (struct elf32_fdpic_loadaddr *loadaddr, void *got_value,
+ struct elf32_fdpic_loadmap *map)
+{
+ if (map->version != 0)
+ {
+ SEND_EARLY_STDERR ("Invalid loadmap version number\n");
+ _dl_exit(-1);
+ }
+ if (map->nsegs == 0)
+ {
+ SEND_EARLY_STDERR ("Invalid segment count in loadmap\n");
+ _dl_exit(-1);
+ }
+ loadaddr->got_value = got_value;
+ loadaddr->map = map;
+}
+
+/* Figure out how many LOAD segments there are in the given headers,
+ and allocate a block for the load map big enough for them.
+ got_value will be properly initialized later on, with INIT_GOT. */
+inline static int
+__dl_init_loadaddr (struct elf32_fdpic_loadaddr *loadaddr, Elf32_Phdr *ppnt,
+ int pcnt)
+{
+ int count = 0, i;
+ size_t size;
+
+ for (i = 0; i < pcnt; i++)
+ if (ppnt[i].p_type == PT_LOAD)
+ count++;
+
+ loadaddr->got_value = 0;
+
+ size = sizeof (struct elf32_fdpic_loadmap)
+ + sizeof (struct elf32_fdpic_loadseg) * count;
+ loadaddr->map = _dl_malloc (size);
+ if (! loadaddr->map)
+ _dl_exit (-1);
+
+ loadaddr->map->version = 0;
+ loadaddr->map->nsegs = 0;
+
+ return count;
+}
+
+/* Incrementally initialize a load map. */
+inline static void
+__dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void