diff options
39 files changed, 3996 insertions, 1 deletions
@@ -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 *addr, + Elf32_Phdr *phdr, int maxsegs) +{ + struct elf32_fdpic_loadseg *segdata; + + if (loadaddr.map->nsegs == maxsegs) + _dl_exit (-1); + + segdata = &loadaddr.map->segs[loadaddr.map->nsegs++]; + segdata->addr = (Elf32_Addr) addr; + segdata->p_vaddr = phdr->p_vaddr; + segdata->p_memsz = phdr->p_memsz; + +#if defined (__SUPPORT_LD_DEBUG__) + { + extern char *_dl_debug; + extern int _dl_debug_file; + if (_dl_debug) + _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n", + loadaddr.map->nsegs-1, + segdata->p_vaddr, segdata->addr, segdata->p_memsz); + } +#endif +} + +inline static void __dl_loadaddr_unmap +(struct elf32_fdpic_loadaddr loadaddr, struct funcdesc_ht *funcdesc_ht); + +/* Figure out whether the given address is in one of the mapped + segments. */ +inline static int +__dl_addr_in_loadaddr (void *p, struct elf32_fdpic_loadaddr loadaddr) +{ + struct elf32_fdpic_loadmap *map = loadaddr.map; + int c; + + for (c = 0; c < map->nsegs; c++) + if ((void*)map->segs[c].addr <= p + && (char*)p < (char*)map->segs[c].addr + map->segs[c].p_memsz) + return 1; + + return 0; +} + +inline static void * _dl_funcdesc_for (void *entry_point, void *got_value); + +#define DL_LOADADDR_TYPE struct elf32_fdpic_loadaddr + +#define DL_RELOC_ADDR(ADDR, LOADADDR) \ + (__reloc_pointer ((void*)(ADDR), (LOADADDR).map)) + +#define DL_ADDR_TO_FUNC_PTR(ADDR, LOADADDR) \ + ((void(*)(void)) _dl_funcdesc_for ((void*)(ADDR), (LOADADDR).got_value)) + +#define _dl_stabilize_funcdesc(val) \ + ({ asm ("" : "+m" (*(val))); (val); }) + +#define DL_CALL_FUNC_AT_ADDR(ADDR, LOADADDR, SIGNATURE, ...) \ + ({ struct funcdesc_value fd = { (void*)(ADDR), (LOADADDR).got_value }; \ + void (*pf)(void) = (void*) _dl_stabilize_funcdesc (&fd); \ + (* SIGNATURE pf)(__VA_ARGS__); }) + +#define DL_INIT_LOADADDR_BOOT(LOADADDR, BASEADDR) \ + (__dl_init_loadaddr_map (&(LOADADDR), dl_boot_got_pointer, \ + dl_boot_ldsomap ?: dl_boot_progmap)) + +#define DL_INIT_LOADADDR_PROG(LOADADDR, BASEADDR) \ + (__dl_init_loadaddr_map (&(LOADADDR), 0, dl_boot_progmap)) + +#define DL_INIT_LOADADDR_EXTRA_DECLS \ + int dl_init_loadaddr_load_count; +#define DL_INIT_LOADADDR(LOADADDR, BASEADDR, PHDR, PHDRCNT) \ + (dl_init_loadaddr_load_count = \ + __dl_init_loadaddr (&(LOADADDR), (PHDR), (PHDRCNT))) +#define DL_INIT_LOADADDR_HDR(LOADADDR, ADDR, PHDR) \ + (__dl_init_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR), \ + dl_init_loadaddr_load_count)) +#define DL_LOADADDR_UNMAP(LOADADDR, LEN) \ + (__dl_loadaddr_unmap ((LOADADDR), (NULL))) +#define DL_LIB_UNMAP(LIB, LEN) \ + (__dl_loadaddr_unmap ((LIB)->loadaddr, (LIB)->funcdesc_ht)) +#define DL_LOADADDR_BASE(LOADADDR) \ + ((LOADADDR).got_value) + +#define DL_ADDR_IN_LOADADDR(ADDR, TPNT, TFROM) \ + (! (TFROM) && __dl_addr_in_loadaddr ((void*)(ADDR), (TPNT)->loadaddr)) + +/* We only support loading FDPIC independently-relocatable shared + libraries. It probably wouldn't be too hard to support loading + shared libraries that require relocation by the same amount, but we + don't know that they exist or would be useful, and the dynamic + loader code could leak the whole-library map unless we keeping a + bit more state for DL_LOADADDR_UNMAP and DL_LIB_UNMAP, so let's + keep things simple for now. */ +#define DL_CHECK_LIB_TYPE(epnt, piclib, _dl_progname, libname) \ +do \ +{ \ + if (((epnt)->e_flags & EF_FRV_FDPIC) && ! ((epnt)->e_flags & EF_FRV_PIC)) \ + (piclib) = 2; \ + else \ + { \ + _dl_internal_error_number = LD_ERROR_NOTDYN; \ + _dl_dprintf(2, "%s: '%s' is not an FDPIC shared library" \ + "\n", (_dl_progname), (libname)); \ + _dl_close(infile); \ + return NULL; \ + } \ +} \ +while (0) + +/* We want want to apply all relocations in the interpreter during + bootstrap. Because of this, we have to skip the interpreter + relocations in _dl_parse_relocation_information(), see + elfinterp.c. */ +#define DL_SKIP_BOOTSTRAP_RELOC(SYMTAB, INDEX, STRTAB) 0 + +#ifdef __NR_pread +#define _DL_PREAD(FD, BUF, SIZE, OFFSET) \ + (_dl_pread((FD), (BUF), (SIZE), (OFFSET))) +#endif + +#include <dl-hash.h> + +/* The hashcode handling code below is heavily inspired in libiberty's + hashtab code, but with most adaptation points and support for + deleting elements removed. + + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Vladimir Makarov (vmakarov@cygnus.com). */ + +inline static unsigned long +higher_prime_number (unsigned long n) +{ + /* These are primes that are near, but slightly smaller than, a + power of two. */ + static const unsigned long primes[] = { + (unsigned long) 7, + (unsigned long) 13, + (unsigned long) 31, + (unsigned long) 61, + (unsigned long) 127, + (unsigned long) 251, + (unsigned long) 509, + (unsigned long) 1021, + (unsigned long) 2039, + (unsigned long) 4093, + (unsigned long) 8191, + (unsigned long) 16381, + (unsigned long) 32749, + (unsigned long) 65521, + (unsigned long) 131071, + (unsigned long) 262139, + (unsigned long) 524287, + (unsigned long) 1048573, + (unsigned long) 2097143, + (unsigned long) 4194301, + (unsigned long) 8388593, + (unsigned long) 16777213, + (unsigned long) 33554393, + (unsigned long) 67108859, + (unsigned long) 134217689, + (unsigned long) 268435399, + (unsigned long) 536870909, + (unsigned long) 1073741789, + (unsigned long) 2147483647, + /* 4294967291L */ + ((unsigned long) 2147483647) + ((unsigned long) 2147483644), + }; + + const unsigned long *low = &primes[0]; + const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])]; + + while (low != high) + { + const unsigned long *mid = low + (high - low) / 2; + if (n > *mid) + low = mid + 1; + else + high = mid; + } + +#if 0 + /* If we've run out of primes, abort. */ + if (n > *low) + { + fprintf (stderr, "Cannot find prime bigger than %lu\n", n); + abort (); + } +#endif + + return *low; +} + +struct funcdesc_ht +{ + /* Table itself. */ + struct funcdesc_value **entries; + + /* Current size (in entries) of the hash table */ + size_t size; + + /* Current number of elements. */ + size_t n_elements; +}; + +inline static int +hash_pointer (const void *p) +{ + return (int) ((long)p >> 3); +} + +inline static struct funcdesc_ht * +htab_create (void) +{ + struct funcdesc_ht *ht = _dl_malloc (sizeof (struct funcdesc_ht)); + + if (! ht) + return NULL; + ht->size = 3; + ht->entries = _dl_malloc (sizeof (struct funcdesc_ht_value *) * ht->size); + if (! ht->entries) + return NULL; + + ht->n_elements = 0; + + _dl_memset (ht->entries, 0, sizeof (struct funcdesc_ht_value *) * ht->size); + + return ht; +} + +inline static void +htab_delete (struct funcdesc_ht *htab) +{ + int i; + + for (i = htab->size - 1; i >= 0; i--) + if (htab->entries[i]) + _dl_free (htab->entries[i]); + + _dl_free (htab->entries); + _dl_free (htab); +} + +/* Similar to htab_find_slot, but without several unwanted side effects: + - Does not call htab->eq_f when it finds an existing entry. + - Does not change the count of elements/searches/collisions in the + hash table. + This function also assumes there are no deleted entries in the table. + HASH is the hash value for the element to be inserted. */ + +inline static struct funcdesc_value ** +find_empty_slot_for_expand (struct funcdesc_ht *htab, int hash) +{ + size_t size = htab->size; + unsigned int index = hash % size; + struct funcdesc_value **slot = htab->entries + index; + int hash2; + + if (! *slot) + return slot; + + hash2 = 1 + hash % (size - 2); + for (;;) + { + index += hash2; + if (index >= size) + index -= size; + + slot = htab->entries + index; + if (! *slot) + return slot; + } +} + +/* The following function changes size of memory allocated for the + entries and repeatedly inserts the table elements. The occupancy + of the table after the call will be about 50%. Naturally the hash + table must already exist. Remember also that the place of the + table entries is changed. If memory allocation failures are allowed, + this function will return zero, indicating that the table could not be + expanded. If all goes well, it will return a non-zero value. */ + +inline static int +htab_expand (struct funcdesc_ht *htab) +{ + struct funcdesc_value **oentries; + struct funcdesc_value **olimit; + struct funcdesc_value **p; + struct funcdesc_value **nentries; + size_t nsize; + + oentries = htab->entries; + olimit = oentries + htab->size; + + /* Resize only when table after removal of unused elements is either + too full or too empty. */ + if (htab->n_elements * 2 > htab->size) + nsize = higher_prime_number (htab->n_elements * 2); + else + nsize = htab->size; + + nentries = _dl_malloc (sizeof (struct funcdesc_value *) * nsize); + _dl_memset (nentries, 0, sizeof (struct funcdesc_value *) * nsize); + if (nentries == NULL) + return 0; + htab->entries = nentries; + htab->size = nsize; + + p = oentries; + do + { + if (*p) + *find_empty_slot_for_expand (htab, hash_pointer ((*p)->entry_point)) + = *p; + + p++; + } + while (p < olimit); + + _dl_free (oentries); + return 1; +} + +/* This function searches for a hash table slot containing an entry + equal to the given element. To delete an entry, call this with + INSERT = 0, then call htab_clear_slot on the slot returned (possibly + after doing some checks). To insert an entry, call this with + INSERT = 1, then write the value you want into the returned slot. + When inserting an entry, NULL may be returned if memory allocation + fails. */ + +inline static struct funcdesc_value ** +htab_find_slot (struct funcdesc_ht *htab, void *ptr) +{ + unsigned int index; + int hash, hash2; + size_t size; + struct funcdesc_value **entry; + + if (htab->size * 3 <= htab->n_elements * 4 + && htab_expand (htab) == 0) + return NULL; + + hash = hash_pointer (ptr); + + size = htab->size; + index = hash % size; + + entry = &htab->entries[index]; + if (!*entry) + goto empty_entry; + else if ((*entry)->entry_point == ptr) + return entry; + + hash2 = 1 + hash % (size - 2); + for (;;) + { + index += hash2; + if (index >= size) + index -= size; + + entry = &htab->entries[index]; + if (!*entry) + goto empty_entry; + else if ((*entry)->entry_point == ptr) + return entry; + } + + empty_entry: + htab->n_elements++; + return entry; +} + +void * +_dl_funcdesc_for (void *entry_point, void *got_value) +{ + struct elf_resolve *tpnt = ((void**)got_value)[2]; + struct funcdesc_ht *ht = tpnt->funcdesc_ht; + struct funcdesc_value **entry; + + _dl_assert (got_value == tpnt->loadaddr.got_value); + + if (! ht) + { + ht = htab_create (); + if (! ht) + return (void*)-1; + tpnt->funcdesc_ht = ht; + } + + entry = htab_find_slot (ht, entry_point); + if (*entry) + { + _dl_assert ((*entry)->entry_point == entry_point); + return _dl_stabilize_funcdesc (*entry); + } + + *entry = _dl_malloc (sizeof (struct funcdesc_value)); + (*entry)->entry_point = entry_point; + (*entry)->got_value = got_value; + + return _dl_stabilize_funcdesc (*entry); +} + +void +__dl_loadaddr_unmap (struct elf32_fdpic_loadaddr loadaddr, + struct funcdesc_ht *funcdesc_ht) +{ + int i; + + for (i = 0; i < loadaddr.map->nsegs; i++) + _dl_munmap ((void*)loadaddr.map->segs[i].addr, + loadaddr.map->segs[i].p_memsz); + + _dl_free (loadaddr.map); + if (funcdesc_ht) + htab_delete (funcdesc_ht); +} diff --git a/ldso/ldso/frv/elfinterp.c b/ldso/ldso/frv/elfinterp.c new file mode 100644 index 000000000..270a5a60e --- /dev/null +++ b/ldso/ldso/frv/elfinterp.c @@ -0,0 +1,495 @@ +/* FR-V FDPIC ELF shared library loader suppport + Copyright (C) 2003 Red Hat, Inc. + Contributed by Alexandre Oliva <aoliva@redhat.com> + Lots of code copied from ../i386/elfinterp.c, so: + Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + David Engel, Hongjiu Lu and Mitch D'Souza + Copyright (C) 2001-2002, Erik Andersen + All rights reserved. + +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. */ + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__((__unused__)) +#endif + +#if defined (__SUPPORT_LD_DEBUG__) +static const char *_dl_reltypes_tab[] = +{ + [0] "R_FRV_NONE", "R_FRV_32", + [2] "R_FRV_LABEL16", "R_FRV_LABEL24", + [4] "R_FRV_LO16", "R_FRV_HI16", + [6] "R_FRV_GPREL12", "R_FRV_GPRELU12", + [8] "R_FRV_GPREL32", "R_FRV_GPRELHI", "R_FRV_GPRELLO", + [11] "R_FRV_GOT12", "R_FRV_GOTHI", "R_FRV_GOTLO", + [14] "R_FRV_FUNCDESC", + [15] "R_FRV_FUNCDESC_GOT12", "R_FRV_FUNCDESC_GOTHI", "R_FRV_FUNCDESC_GOTLO", + [18] "R_FRV_FUNCDESC_VALUE", "R_FRV_FUNCDESC_GOTOFF12", + [20] "R_FRV_FUNCDESC_GOTOFFHI", "R_FRV_FUNCDESC_GOTOFFLO", + [22] "R_FRV_GOTOFF12", "R_FRV_GOTOFFHI", "R_FRV_GOTOFFLO", +#if 0 + [200] "R_FRV_GNU_VTINHERIT", "R_FRV_GNU_VTENTRY" +#endif +}; + +static const char * +_dl_reltypes(int type) +{ + static char buf[22]; + const char *str; + + if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) || + NULL == (str = _dl_reltypes_tab[type])) + { + str =_dl_simple_ltoa( buf, (unsigned long)(type)); + } + return str; +} + +static +void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index) +{ + if(_dl_debug_symbols) + { + if(symtab_index){ + _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x", + strtab + symtab[symtab_index].st_name, + symtab[symtab_index].st_value, + symtab[symtab_index].st_size, + symtab[symtab_index].st_info, + symtab[symtab_index].st_other, + symtab[symtab_index].st_shndx); + } + } +} + +static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt) +{ + if(_dl_debug_reloc) + { + int symtab_index; + const char *sym; + symtab_index = ELF32_R_SYM(rpnt->r_info); + sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0"; + + if(_dl_debug_symbols) + _dl_dprintf(_dl_debug_file, "\n\t"); + else + _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym); +#ifdef ELF_USES_RELOCA + _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x", + _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), + rpnt->r_offset, + rpnt->r_addend); +#else + _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n", + _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), + rpnt->r_offset); +#endif + } +} +#endif + +/* Program to load an ELF binary on a linux system, and run it. + References to symbols in sharable libraries can be resolved by either + an ELF sharable library or a linux style of shared library. */ + +/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have + I ever taken any courses on internals. This program was developed using + information available through the book "UNIX SYSTEM V RELEASE 4, + Programmers guide: Ansi C and Programming Support Tools", which did + a more than adequate job of explaining everything required to get this + working. */ + +struct funcdesc_value volatile *__attribute__((__visibility__("hidden"))) +_dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry) +{ + int reloc_type; + ELF_RELOC *this_reloc; + char *strtab; + Elf32_Sym *symtab; + int symtab_index; + char *rel_addr; + struct elf_resolve *new_tpnt; + char *new_addr; + struct funcdesc_value funcval; + struct funcdesc_value volatile *got_entry; + char *symname; + + rel_addr = DL_RELOC_ADDR (tpnt->dynamic_info[DT_JMPREL], + tpnt->loadaddr); + + this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry); + reloc_type = ELF32_R_TYPE(this_reloc->r_info); + symtab_index = ELF32_R_SYM(this_reloc->r_info); + + symtab = (Elf32_Sym *)(intptr_t) + DL_RELOC_ADDR (tpnt->dynamic_info[DT_SYMTAB], + tpnt->loadaddr); + strtab = DL_RELOC_ADDR (tpnt->dynamic_info[DT_STRTAB], tpnt->loadaddr); + symname= strtab + symtab[symtab_index].st_name; + + if (reloc_type != R_FRV_FUNCDESC_VALUE) { + _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", + _dl_progname); + _dl_exit(1); + } + + /* Address of GOT entry fix up */ + got_entry = (struct funcdesc_value *) + DL_RELOC_ADDR (this_reloc->r_offset, tpnt->loadaddr); + + /* Get the address to be used to fill in the GOT entry. */ + new_addr = __dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver, + &new_tpnt); + if (!new_addr) { + new_addr = __dl_find_hash(symname, NULL, NULL, resolver, + &new_tpnt); + if (!new_addr) { + _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", + _dl_progname, symname); + _dl_exit(1); + } + } + + funcval.entry_point = new_addr; + funcval.got_value = new_tpnt->loadaddr.got_value; + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_bindings) + { + _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname); + if(_dl_debug_detail) + _dl_dprintf(_dl_debug_file, + "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n", + got_entry->entry_point, got_entry->got_value, + funcval.entry_point, funcval.got_value, + got_entry); + } + if (!_dl_debug_nofixups) { + *got_entry = funcval; + } +#else + *got_entry = funcval; +#endif + + return got_entry; +} + +static int +_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)) +{ + unsigned int i; + char *strtab; + Elf32_Sym *symtab; + ELF_RELOC *rpnt; + int symtab_index; + + /* Now parse the relocation information */ + rpnt = (ELF_RELOC *)(intptr_t) DL_RELOC_ADDR (rel_addr, tpnt->loadaddr); + rel_size = rel_size / sizeof(ELF_RELOC); + + symtab = (Elf32_Sym *)(intptr_t) + DL_RELOC_ADDR (tpnt->dynamic_info[DT_SYMTAB], tpnt->loadaddr); + strtab = DL_RELOC_ADDR (tpnt->dynamic_info[DT_STRTAB], tpnt->loadaddr); + + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + + symtab_index = ELF32_R_SYM(rpnt->r_info); + + /* When the dynamic linker bootstrapped itself, it resolved some symbols. + Make sure we do not do them again */ + if (!symtab_index && tpnt->libtype == program_interpreter) + continue; + if (symtab_index && tpnt->libtype == program_interpreter && + _dl_symbol(strtab + symtab[symtab_index].st_name)) + continue; + +#if defined (__SUPPORT_LD_DEBUG__) + debug_sym(symtab,strtab,symtab_index); + debug_reloc(symtab,strtab,rpnt); +#endif + + res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab); + + if (res==0) continue; + + _dl_dprintf(2, "\n%s: ",_dl_progname); + + if (symtab_index) + _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name); + + if (res <0) + { + int reloc_type = ELF32_R_TYPE(rpnt->r_info); +#if defined (__SUPPORT_LD_DEBUG__) + _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type)); +#else + _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type); +#endif + _dl_exit(-res); + } + else if (res >0) + { + _dl_dprintf(2, "can't resolve symbol\n"); + return res; + } + } + return 0; +} + +static int +_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + char *symname; + unsigned long reloc_value = 0, *reloc_addr; + struct { unsigned long v; } __attribute__((__packed__)) + *reloc_addr_packed; + unsigned long symbol_addr; + struct elf_resolve *symbol_tpnt; + struct funcdesc_value funcval; +#if defined (__SUPPORT_LD_DEBUG__) + unsigned long old_val; +#endif + + reloc_addr = (unsigned long *)(intptr_t) + DL_RELOC_ADDR (rpnt->r_offset, tpnt->loadaddr); + asm ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr)); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + symname = strtab + symtab[symtab_index].st_name; + + if (ELF32_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) { + symbol_addr = (unsigned long) + DL_RELOC_ADDR (symtab[symtab_index].st_value, + tpnt->loadaddr); + symbol_tpnt = tpnt; + } else { + + symbol_addr = (unsigned long) + __dl_find_hash(symname, scope, + (reloc_type == R_FRV_FUNCDESC_VALUE + ? tpnt : NULL), symbolrel, + &symbol_tpnt); + + /* + * We want to allow undefined references to weak symbols - this might + * have been intentional. We should not be linking local symbols + * here, so all bases should be covered. + */ + + if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) { +#if defined (__SUPPORT_LD_DEBUG__) + _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n", + symname, tpnt->libname); +#endif + return 0; + } + } + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_reloc && _dl_debug_detail) + { + if ((long)reloc_addr_packed & 3) + old_val = reloc_addr_packed->v; + else + old_val = *reloc_addr; + } + else + old_val = 0; +#endif + switch (reloc_type) { + case R_FRV_NONE: + break; + case R_FRV_32: + if ((long)reloc_addr_packed & 3) + reloc_value = reloc_addr_packed->v += symbol_addr; + else + reloc_value = *reloc_addr += symbol_addr; + break; + case R_FRV_FUNCDESC_VALUE: + funcval.entry_point = (void*)symbol_addr; + /* The addend of FUNCDESC_VALUE + relocations referencing global + symbols must be ignored, because it + may hold the address of a lazy PLT + entry. */ + if (ELF32_ST_BIND + (symtab[symtab_index].st_info) + == STB_LOCAL) + funcval.entry_point += *reloc_addr; + reloc_value = (unsigned long)funcval.entry_point; + if (symbol_addr) + funcval.got_value + = symbol_tpnt->loadaddr.got_value; + else + funcval.got_value = 0; + asm ("std%I0\t%1, %M0" + : "=m" (*(struct funcdesc_value *)reloc_addr) + : "r" (funcval)); + break; + case R_FRV_FUNCDESC: + if ((long)reloc_addr_packed & 3) + reloc_value = reloc_addr_packed->v; + else + reloc_value = *reloc_addr; + if (symbol_addr) + reloc_value = (unsigned long)_dl_funcdesc_for + ((char *)symbol_addr + reloc_value, + symbol_tpnt->loadaddr.got_value); + else + reloc_value = 0; + if ((long)reloc_addr_packed & 3) + reloc_addr_packed->v = reloc_value; + else + *reloc_addr = reloc_value; + break; + default: + return -1; /*call _dl_exit(1) */ + } +#if defined (__SUPPORT_LD_DEBUG__) + if(_dl_debug_reloc && _dl_debug_detail) { + _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr); + switch (reloc_type) { + case R_FRV_FUNCDESC_VALUE: + _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value); + break; + case R_FRV_FUNCDESC: + if (! reloc_value) + break; + _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)", + ((struct funcdesc_value *)reloc_value)->entry_point, + ((struct funcdesc_value *)reloc_value)->got_value); + break; + } + } +#endif + + return 0; +} + +static int +_dl_do_lazy_reloc (struct elf_resolve *tpnt, + struct dyn_elf *scope ATTRIBUTE_UNUSED, + ELF_RELOC *rpnt, Elf32_Sym *symtab ATTRIBUTE_UNUSED, + char *strtab ATTRIBUTE_UNUSED) +{ + int reloc_type; + struct funcdesc_value volatile *reloc_addr; + struct funcdesc_value funcval; +#if defined (__SUPPORT_LD_DEBUG__) + unsigned long old_val; +#endif + + reloc_addr = (struct funcdesc_value *)(intptr_t) + DL_RELOC_ADDR (rpnt->r_offset, tpnt->loadaddr); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + +#if defined (__SUPPORT_LD_DEBUG__) + old_val = (unsigned long)reloc_addr->entry_point; +#endif + switch (reloc_type) { + case R_FRV_NONE: + break; + case R_FRV_FUNCDESC_VALUE: + funcval = *reloc_addr; + funcval.entry_point = + DL_RELOC_ADDR (funcval.entry_point, + tpnt->loadaddr); + funcval.got_value = tpnt->loadaddr.got_value; + *reloc_addr = funcval; + break; + default: + return -1; /*call _dl_exit(1) */ + } +#if defined (__SUPPORT_LD_DEBUG__) + if(_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_addr->entry_point, reloc_addr); +#endif + return 0; + +} + +void +_dl_parse_lazy_relocation_information +(struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size, + int type ATTRIBUTE_UNUSED) +{ + _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +} + +int +_dl_parse_relocation_information +(struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size, + int type ATTRIBUTE_UNUSED) +{ + /* The interpreter initial self-relocation is complete, and we + can't re-apply relocations. */ + if (rpnt->dyn->libtype == program_interpreter) + return 0; + + return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc); +} + +/* We don't have copy relocs. */ + +int +_dl_parse_copy_information +(struct dyn_elf *rpnt ATTRIBUTE_UNUSED, + unsigned long rel_addr ATTRIBUTE_UNUSED, + unsigned long rel_size ATTRIBUTE_UNUSED, + int type ATTRIBUTE_UNUSED) +{ + return 0; +} + +#ifndef LIBDL +# include "../../libc/sysdeps/linux/frv/crtreloc.c" +#endif + +#if ! defined LIBDL || (! defined PIC && ! defined __PIC__) +int +__dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, + size_t size, void *data), void *data) +{ + struct elf_resolve *l; + struct dl_phdr_info info; + int ret = 0; + + for (l = _dl_loaded_modules; l != NULL; l = l->next) + { + info.dlpi_addr = l->loadaddr; + info.dlpi_name = l->libname; + info.dlpi_phdr = l->ppnt; + info.dlpi_phnum = l->n_phent; + ret = callback (&info, sizeof (struct dl_phdr_info), data); + if (ret) + break; + } + + return ret; +} +#endif diff --git a/ldso/ldso/frv/resolve.S b/ldso/ldso/frv/resolve.S new file mode 100644 index 000000000..d9706c746 --- /dev/null +++ b/ldso/ldso/frv/resolve.S @@ -0,0 +1,71 @@ + /* 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. */ + + /* The function below is tail-called by resolver stubs when a + lazily-bound function is called. It must preserve all + registers that could be used to pass arguments to the actual + function. Upon _dl_linux_resolve entry, GR14 holds the + address of a lazy PLT entry, so @(GR14,-4) is the lazy + relocation number that we have to pass to _dl_linux_resolver. + GR15 holds the caller's GOT, from which we extract the + elf_resolve* that _dl_linux_resolver needs as well. + + _dl_linux_resolver() figures out where the jump symbol is + _really_ supposed to have jumped to and returns that to us. + Once we have that, we prepare to tail-call the actual + function, clean up after ourselves, restoring the original + arguments, then jump to the fixed up address. */ + + .text + .p2align 4 + + .hidden _dl_linux_resolve + .global _dl_linux_resolve + .type _dl_linux_resolve,@function + +_dl_linux_resolve: + /* Preserve arguments. */ + addi sp, -8*4, sp + stdi gr8, @(sp, 8) + stdi gr10, @(sp, 16) + stdi gr12, @(sp, 24) + movsg lr,gr8 + st gr8, @(sp,gr0) + + /* Prepare to call _dl_linux_resolver. */ + ldi @(gr15, 8), gr8 + ldi @(gr14, -4), gr9 + mov.p gr5, gr15 + call _dl_linux_resolver + + /* Move aside return value that contains the FUNCDESC_VALUE. */ + ldd @(gr8,gr0),gr14 + + /* Restore arguments. */ + ld @(sp, gr0), gr8 + movgs gr8,lr + lddi @(sp, 24), gr12 + lddi @(sp, 16), gr10 + lddi @(sp, 8), gr8 + addi sp, 8*4, sp + + /* Now jump to the actual function. */ + jmpl @(gr14, gr0) + .size _dl_linux_resolve, . - _dl_linux_resolve diff --git a/libc/sysdeps/linux/frv/Makefile b/libc/sysdeps/linux/frv/Makefile new file mode 100644 index 000000000..77d1326d5 --- /dev/null +++ b/libc/sysdeps/linux/frv/Makefile @@ -0,0 +1,89 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2003 Erik Andersen <andersen@uclibc.org> +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Library General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) any +# later version. +# +# This program 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 Library General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +TOPDIR=../../../../ +include $(TOPDIR)Rules.mak +ASFLAGS=$(CFLAGS) + +CRT0_SRC = crt0.S +CRT0_OBJ = crt0.o crt1.o # gcrt1.o +SCRT0_OBJ = $(patsubst %,S%, $(CRT0_OBJ)) +CRT0_DEPS=gmon-start.S + +CTOR_TARGETS = crti.o crtn.o + +SSRC=__longjmp.S setjmp.S clone.S vfork.S +ifeq ($(strip $(UCLIBC_PROFILING)),y) +SSRC+=mcount.S +endif +SOBJS=$(patsubst %.S,%.o, $(SSRC)) + +CSRC=_mmap.c sysdep.c brk.c sbrk.c __init_brk.c dl-iterate-phdr.c +COBJS=$(patsubst %.c,%.o, $(CSRC)) + +OBJS=$(SOBJS) $(COBJS) + +all: $(OBJS) $(LIBC) + +$(LIBC): ar-target + +ar-target: $(OBJS) $(CRT0_OBJ) $(SCRT0_OBJ) $(CTOR_TARGETS) + $(AR) $(ARFLAGS) $(LIBC) $(OBJS) + $(INSTALL) -d $(TOPDIR)lib + cp $(CRT0_OBJ) $(SCRT0_OBJ) $(CTOR_TARGETS) $(TOPDIR)lib/ + +$(CRT0_OBJ): $(CRT0_SRC) crtreloc.o + $(CC) $(CFLAGS) -DL_$* -r -nostdlib $< crtreloc.o -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + +crtreloc.o: crtreloc.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(SCRT0_OBJ): $(CRT0_SRC) Scrtreloc.o + $(CC) $(CFLAGS) -fPIE -DL_$* -r -nostdlib $< Scrtreloc.o -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + +Scrtreloc.o: crtreloc.c + $(CC) $(CFLAGS) -fPIE -c $< -o $@ + +$(CTOR_TARGETS): %.o : %.S + $(CC) $(CFLAGS) -c $< -o $@ + $(STRIPTOOL) -x -R .note -R .comment $*.o + +$(SOBJS): %.o : %.S + $(CC) $(CFLAGS) -c $< -o $@ + $(STRIPTOOL) -x -R .note -R .comment $*.o + +$(COBJS): %.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + $(STRIPTOOL) -x -R .note -R .comment $*.o + +ifeq ($(strip $(UCLIBC_PROFILING)),y) +SAFECFLAGS := $(filter-out -g,$(CFLAGS)) +gmon-start.S: ../common/gmon-start.c + $(CC) $(SAFECFLAGS) -c $< -S -o $*.S +gcrt1.o: $(CRT0_DEPS) +endif + +headers: + + +clean: + rm -f *.[oa] *~ core + rm -f bits/sysnum.h + diff --git a/libc/sysdeps/linux/frv/__init_brk.c b/libc/sysdeps/linux/frv/__init_brk.c new file mode 100644 index 000000000..7f9cd3c31 --- /dev/null +++ b/libc/sysdeps/linux/frv/__init_brk.c @@ -0,0 +1,25 @@ +/* From libc-5.3.12 */ + +#include <errno.h> +#include <unistd.h> +#include <sys/syscall.h> + +void * ___brk_addr = 0; + +#define __NR__brk __NR_brk +_syscall1(void *, _brk, void *, ptr); + +int +__init_brk (void) +{ + if (___brk_addr == 0) + { + ___brk_addr = _brk(0); + if (___brk_addr == 0) + { + __set_errno(ENOMEM); + return -1; + } + } + return 0; +} diff --git a/libc/sysdeps/linux/frv/__longjmp.S b/libc/sysdeps/linux/frv/__longjmp.S new file mode 100644 index 000000000..a61f8d4e0 --- /dev/null +++ b/libc/sysdeps/linux/frv/__longjmp.S @@ -0,0 +1,75 @@ +#define _SETJMP_H +#define _ASM +#include <bits/setjmp.h> + +# setjmp/longjmp for Frv. The jmpbuf looks like this: +# +# Register jmpbuf offset +# R16-R31 0x0-0x03c +# R48-R63 0x40-0x7c +# FR16-FR31 0x80-0xbc +# FR48-FR63 0xc0-0xfc +# LR 0x100 +# SP 0x104 +# FP 0x108 +# +# R8 contains the pointer to jmpbuf + + .text + .global __longjmp + .type __longjmp,@function +__longjmp: + lddi @(gr8,0), gr16 + lddi @(gr8,8), gr18 + lddi @(gr8,16), gr20 + lddi @(gr8,24), gr22 + lddi @(gr8,32), gr24 + lddi @(gr8,40), gr26 + lddi @(gr8,48), gr28 + lddi @(gr8,56), gr30 +#if __FRV_GPR__ != 32 + lddi @(gr8,64), gr48 + lddi @(gr8,72), gr50 + lddi @(gr8,80), gr52 + lddi @(gr8,88), gr54 + lddi @(gr8,96), gr56 + lddi @(gr8,104), gr58 + lddi @(gr8,112), gr60 + lddi @(gr8,120), gr62 +#endif + +#if __FRV_FPR__ != 0 + lddfi @(gr8,128), fr16 + lddfi @(gr8,136), fr18 + lddfi @(gr8,144), fr20 + lddfi @(gr8,152), fr22 + lddfi @(gr8,160), fr24 + lddfi @(gr8,168), fr26 + lddfi @(gr8,176), fr28 + lddfi @(gr8,184), fr30 +#if __FRV_FPR__ != 32 + lddfi @(gr8,192), fr48 + lddfi @(gr8,200), fr50 + lddfi @(gr8,208), fr52 + lddfi @(gr8,216), fr54 + lddfi @(gr8,224), fr56 + lddfi @(gr8,232), fr58 + lddfi @(gr8,240), fr60 + lddfi @(gr8,248), fr62 +#endif +#endif + + ldi @(gr8,256), gr4 + movgs gr4,lr + + ldi @(gr8,260), sp + ldi @(gr8,264), fp + +# Value to return is in r9. If zero, return 1 + cmp gr9, gr0, icc0 + setlos #1, gr8 + ckne icc0, cc4 + cmov gr9, gr8, cc4, 1 + ret +.Lend2: + .size __longjmp,.Lend2-__longjmp diff --git a/libc/sysdeps/linux/frv/_mmap.c b/libc/sysdeps/linux/frv/_mmap.c new file mode 100644 index 000000000..b3fd7c3d8 --- /dev/null +++ b/libc/sysdeps/linux/frv/_mmap.c @@ -0,0 +1,48 @@ +/* Copyright (C) 1997, 1998, 1999, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Daniel Jacobowitz <dan@debian.org>, 1999. + + 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. */ + +/* Massivly hacked up for uClibc by Erik Andersen */ + +/* Extracted from ../common/mmap64.c by Alexandre Oliva <aoliva@redhat.com> + + We don't want to use the old mmap interface. */ + +#include <features.h> +#include <errno.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <sys/mman.h> + +#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 + +__ptr_t mmap(__ptr_t addr, size_t len, int prot, int flags, int fd, __off_t offset) +{ + if (offset & ((1 << MMAP2_PAGE_SHIFT) - 1)) { + __set_errno (EINVAL); + return MAP_FAILED; + } + return(__syscall_mmap2(addr, len, prot, flags, fd, (off_t) (offset >> MMAP2_PAGE_SHIFT))); +} diff --git a/libc/sysdeps/linux/frv/bits/elf-fdpic.h b/libc/sysdeps/linux/frv/bits/elf-fdpic.h new file mode 100644 index 000000000..f47d9493c --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/elf-fdpic.h @@ -0,0 +1,104 @@ +/* Copyright 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 +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 +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 GR8 at start-up, and a pointer to + an additional such map is passed in GR9 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. */ +inline static 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 explicitly refrain from checking for one-past-the-end. + Zero-sized objects aren't legal, and it's expected that array + addresses will be relocated before the addend that would make + it one-past-the-end is added. This gives us a reasonable speed + up, and we couldn't possibly disambiguate all cases anyway. */ + if (offset < map->segs[c].p_memsz) + 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/frv/bits/endian.h b/libc/sysdeps/linux/frv/bits/endian.h new file mode 100644 index 000000000..0564c5921 --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/endian.h @@ -0,0 +1,7 @@ +/* frv is little-endian. */ + +#ifndef _ENDIAN_H +# error "Never use <bits/endian.h> directly; include <endian.h> instead." +#endif + +#define __BYTE_ORDER __BIG_ENDIAN diff --git a/libc/sysdeps/linux/frv/bits/fcntl.h b/libc/sysdeps/linux/frv/bits/fcntl.h new file mode 100644 index 000000000..69a20966d --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/fcntl.h @@ -0,0 +1,156 @@ +/* O_*, F_*, FD_* bit values for Linux. + Copyright (C) 1995, 1996, 1997, 1998, 2000 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 _FCNTL_H +# error "Never use <bits/fcntl.h> directly; include <fcntl.h> instead." +#endif + + +#include <sys/types.h> + +/* open/fcntl - O_SYNC is only implemented on blocks devices and on files + located on an ext2 file system */ +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 /* not fcntl */ +#define O_EXCL 0200 /* not fcntl */ +#define O_NOCTTY 0400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_NDELAY O_NONBLOCK +#define O_SYNC 010000 +#define O_FSYNC O_SYNC +#define O_ASYNC 020000 + +#ifdef __USE_GNU +# define O_DIRECT 040000 /* Direct disk access. */ +# define O_DIRECTORY 0200000 /* Must be a directory. */ +# define O_NOFOLLOW 0400000 /* Do not follow links. */ +# define O_STREAMING 04000000/* streaming access */ +#endif + +/* For now Linux has synchronisity options for data and read operations. + We define the symbols here but let them do the same as O_SYNC since + this is a superset. */ +#if defined __USE_POSIX199309 || defined __USE_UNIX98 +# define O_DSYNC O_SYNC /* Synchronize data. */ +# define O_RSYNC O_SYNC /* Synchronize read operations. */ +#endif + +#ifdef __USE_LARGEFILE64 +# define O_LARGEFILE 0100000 +#endif + +/* Values for the second argument to `fcntl'. */ +#define F_DUPFD 0 /* Duplicate file descriptor. */ +#define F_GETFD 1 /* Get file descriptor flags. */ +#define F_SETFD 2 /* Set file descriptor flags. */ +#define F_GETFL 3 /* Get file status flags. */ +#define F_SETFL 4 /* Set file status flags. */ +#ifndef __USE_FILE_OFFSET64 +# define F_GETLK 5 /* Get record locking info. */ +# define F_SETLK 6 /* Set record locking info (non-blocking). */ +# define F_SETLKW 7 /* Set record locking info (blocking). */ +#else +# define F_GETLK F_GETLK64 /* Get record locking info. */ +# define F_SETLK F_SETLK64 /* Set record locking info (non-blocking).*/ +# define F_SETLKW F_SETLKW64 /* Set record locking info (blocking). */ +#endif +#define F_GETLK64 12 /* Get record locking info. */ +#define F_SETLK64 13 /* Set record locking info (non-blocking). */ +#define F_SETLKW64 14 /* Set record locking info (blocking). */ + +#if defined __USE_BSD || defined __USE_XOPEN2K +# define F_SETOWN 8 /* Get owner of socket (receiver of SIGIO). */ +# define F_GETOWN 9 /* Set owner of socket (receiver of SIGIO). */ +#endif + +#ifdef __USE_GNU +# define F_SETSIG 10 /* Set number of signal to be sent. */ +# define F_GETSIG 11 /* Get number of signal to be sent. */ +#endif + +/* For F_[GET|SET]FL. */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* For posix fcntl() and `l_type' field of a `struct flock' for lockf(). */ +#define F_RDLCK 0 /* Read lock. */ +#define F_WRLCK 1 /* Write lock. */ +#define F_UNLCK 2 /* Remove lock. */ + +/* For old implementation of bsd flock(). */ +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ + +#ifdef __USE_BSD +/* Operations for bsd flock(), also used by the kernel implementation. */ +# define LOCK_SH 1 /* shared lock */ +# define LOCK_EX 2 /* exclusive lock */ +# define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +# define LOCK_UN 8 /* remove lock */ +#endif + +struct flock + { + short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ + short int l_whence; /* Where `l_start' is relative to (like `lseek'). */ +#ifndef __USE_FILE_OFFSET64 + __off_t l_start; /* Offset where the lock begins. */ + __off_t l_len; /* Size of the locked area; zero means until EOF. */ +#else + __off64_t l_start; /* Offset where the lock begins. */ + __off64_t l_len; /* Size of the locked area; zero means until EOF. */ +#endif + __pid_t l_pid; /* Process holding the lock. */ + }; + +#ifdef __USE_LARGEFILE64 +struct flock64 + { + short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ + short int l_whence; /* Where `l_start' is relative to (like `lseek'). */ + __off64_t l_start; /* Offset where the lock begins. */ + __off64_t l_len; /* Size of the locked area; zero means until EOF. */ + __pid_t l_pid; /* Process holding the lock. */ + }; +#endif + +/* Define some more compatibility macros to be backward compatible with + BSD systems which did not managed to hide these kernel macros. */ +#ifdef __USE_BSD +# define FAPPEND O_APPEND +# define FFSYNC O_FSYNC +# define FASYNC O_ASYNC +# define FNONBLOCK O_NONBLOCK +# define FNDELAY O_NDELAY +#endif /* Use BSD. */ + +/* Advise to `posix_fadvise'. */ +#ifdef __USE_XOPEN2K +# define POSIX_FADV_NORMAL 0 /* No further special treatment. */ +# define POSIX_FADV_RANDOM 1 /* Expect random page references. */ +# define POSIX_FADV_SEQUENTIAL 2 /* Expect sequential page references. */ +# define POSIX_FADV_WILLNEED 3 /* Will need these pages. */ +# define POSIX_FADV_DONTNEED 4 /* Don't need these pages. */ +# define POSIX_FADV_NOREUSE 5 /* Data will be accessed once. */ +#endif diff --git a/libc/sysdeps/linux/frv/bits/kernel_stat.h b/libc/sysdeps/linux/frv/bits/kernel_stat.h new file mode 100644 index 000000000..c6fc95328 --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/kernel_stat.h @@ -0,0 +1,57 @@ +#ifndef _BITS_STAT_STRUCT_H +#define _BITS_STAT_STRUCT_H + +/* This file provides whatever this particular arch's kernel thinks + * struct kernel_stat should look like... It turns out each arch has a + * different opinion on the subject... */ + +struct kernel_stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long __unused1; + unsigned long st_mtime; + unsigned long __unused2; + unsigned long st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +struct kernel_stat64 { + unsigned char __pad0[6]; + unsigned short st_dev; + unsigned char __pad1[2]; +#define _HAVE_STAT64___ST_INO + unsigned long __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned long st_uid; + unsigned long st_gid; + unsigned char __pad2[6]; + unsigned short st_rdev; + unsigned char __pad3[2]; + long long st_size; + unsigned long st_blksize; + unsigned long __pad4; /* future possible st_blocks high bits */ + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ + unsigned long st_atime; + unsigned long __pad5; + unsigned long st_mtime; + unsigned long __pad6; + unsigned long st_ctime; + unsigned long __pad7; /* will be high 32 bits of ctime someday */ + unsigned long long st_ino; +}; + +#endif /* _BITS_STAT_STRUCT_H */ diff --git a/libc/sysdeps/linux/frv/bits/kernel_types.h b/libc/sysdeps/linux/frv/bits/kernel_types.h new file mode 100644 index 000000000..3d3f6304c --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/kernel_types.h @@ -0,0 +1,43 @@ +/* Note that we use the exact same include guard #define names + * as asm/posix_types.h. This will avoid gratuitous conflicts + * with the posix_types.h kernel header, and will ensure that + * our private content, and not the kernel header, will win. + * -Erik + */ +#ifndef _ASM_POSIX_TYPES_H +#define _ASM_POSIX_TYPES_H + +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +typedef long long __kernel_loff_t; + +typedef struct { +#ifdef __USE_ALL + int val[2]; +#else + int __val[2]; +#endif +} __kernel_fsid_t; + +#endif /* _ASM_POSIX_TYPES_H */ diff --git a/libc/sysdeps/linux/frv/bits/mman.h b/libc/sysdeps/linux/frv/bits/mman.h new file mode 100644 index 000000000..9e87f804c --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/mman.h @@ -0,0 +1,75 @@ +/* Definitions for POSIX memory map interface. Linux/frv version. + Copyright (C) 1997 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_MMAN_H +# error "Never use <bits/mman.h> directly; include <sys/mman.h> instead." +#endif + +/* The following definitions basically come from the kernel headers. + But the kernel header is not namespace clean. */ + + +/* Protections are chosen from these bits, OR'd together. The + implementation does not necessarily support PROT_EXEC or PROT_WRITE + without PROT_READ. The only guarantees are that no writing will be + allowed without PROT_WRITE and no access will be allowed for PROT_NONE. */ + +#define PROT_READ 0x1 /* Page can be read. */ +#define PROT_WRITE 0x2 /* Page can be written. */ +#define PROT_EXEC 0x4 /* Page can be executed. */ +#define PROT_NONE 0x0 /* Page can not be accessed. */ + +/* Sharing types (must choose one and only one of these). */ +#define MAP_SHARED 0x01 /* Share changes. */ +#define MAP_PRIVATE 0x02 /* Changes are private. */ +#ifdef __USE_MISC +# define MAP_TYPE 0x0f /* Mask for type of mapping. */ +#endif + +/* Other flags. */ +#define MAP_FIXED 0x10 /* Interpret addr exactly. */ +#ifdef __USE_MISC +# define MAP_FILE 0 +# define MAP_ANONYMOUS 0x20 /* Don't use a file. */ +# define MAP_ANON MAP_ANONYMOUS +#endif + +/* These are Linux-specific. */ +#ifdef __USE_MISC +# define MAP_GROWSDOWN 0x0100 /* Stack-like segment. */ +# define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +# define MAP_EXECUTABLE 0x1000 /* Mark it as an executable. */ +# define MAP_LOCKED 0x2000 /* Lock the mapping. */ +# define MAP_NORESERVE 0x4000 /* Don't check for reservations. */ +#endif + +/* Flags to `msync'. */ +#define MS_ASYNC 1 /* Sync memory asynchronously. */ +#define MS_SYNC 4 /* Synchronous memory sync. */ +#define MS_INVALIDATE 2 /* Invalidate the caches. */ + +/* Flags for `mlockall'. */ +#define MCL_CURRENT 1 /* Lock all currently mapped pages. */ +#define MCL_FUTURE 2 /* Lock all additions to address + space. */ + +/* Flags for `mremap'. */ +#ifdef __USE_GNU +# define MREMAP_MAYMOVE 1 +#endif diff --git a/libc/sysdeps/linux/frv/bits/setjmp.h b/libc/sysdeps/linux/frv/bits/setjmp.h new file mode 100644 index 000000000..5c20c4f54 --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/setjmp.h @@ -0,0 +1,53 @@ +/* Copyright (C) 1999, 2000, 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Define the machine-dependent type `jmp_buf'. FRV version. */ + +#ifndef _SETJMP_H +# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead." +#endif + +#define __SETJMP_NUM_INT 32 /* number of integer registers to save */ +#define __SETJMP_NUM_DBL 32 /* number of double registers to save */ + +#define __SETJMP_INT(x) (x) +#define __SETJMP_DBL(x) (__SETJMP_NUM_INT+(x)) +#define __SETJMP_LR (__SETJMP_NUM_INT+__SETJMP_NUM_DBL) +#define __SETJMP_SP (__SETJMP_LR+1) +#define __SETJMP_FP (__SETJMP_SP+1) + + +#ifndef _ASM +typedef struct +/* Demand 64-bit alignment such that we can use std/ldd in + setjmp/longjmp. */ +__attribute__((__aligned__(8))) + { + /* Callee-saved registers. */ + unsigned long __ints[__SETJMP_NUM_INT]; /* integer registers */ + unsigned long __dbls[__SETJMP_NUM_DBL]; /* double registers */ + unsigned long __lr; /* linkage register */ + unsigned long __sp; /* stack pointer */ + unsigned long __fp; /* frame pointer */ + } __jmp_buf[1]; +#endif + +/* Test if longjmp to JMPBUF would unwind the frame + containing a local variable at ADDRESS. */ +#define _JMPBUF_UNWINDS(jmpbuf, address) \ + ((unsigned long) (address) < (jmpbuf)->__sp) diff --git a/libc/sysdeps/linux/frv/bits/stackinfo.h b/libc/sysdeps/linux/frv/bits/stackinfo.h new file mode 100644 index 000000000..03412e009 --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/stackinfo.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2001 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. */ + +/* This file contains a bit of information about the stack allocation + of the processor. */ + +#ifndef _STACKINFO_H +#define _STACKINFO_H 1 + +/* On FRV the stack grows down. */ +#define _STACK_GROWS_DOWN 1 + +#endif /* stackinfo.h */ diff --git a/libc/sysdeps/linux/frv/bits/syscalls.h b/libc/sysdeps/linux/frv/bits/syscalls.h new file mode 100644 index 000000000..552f7e7c4 --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/syscalls.h @@ -0,0 +1,129 @@ +#ifndef _BITS_SYSCALLS_H +#define _BITS_SYSCALLS_H +#ifndef _SYSCALL_H +# error "Never use <bits/syscalls.h> directly; include <sys/syscall.h> instead." +#endif + +/* This includes the `__NR_<name>' syscall numbers taken from the Linux kernel + * header files. It also defines the traditional `SYS_<name>' macros for older + * programs. */ +#include <bits/sysnum.h> + +#ifndef __set_errno +# define __set_errno(val) ((*__errno_location ()) = (val)) +#endif +#ifndef SYS_ify +# define SYS_ify(syscall_name) (__NR_##syscall_name) +#endif + +#ifndef __ASSEMBLER__ + +/* user-visible error numbers are in the range -1 - -4095: see <asm-frv/errno.h> */ +#define __syscall_return(type, res) \ +do { \ + unsigned long __sr2 = (res); \ + if ((unsigned long)(__sr2) >= (unsigned long)(-4095)) { \ + __set_errno (-(__sr2)); \ + __sr2 = -1; \ + } \ + return (type) (__sr2); \ +} while (0) + +/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ + +#define _syscall0(type,name) \ +type name(void) \ +{ \ +register unsigned long __scnum __asm__ ("gr7") = (__NR_##name); \ +register unsigned long __sc0 __asm__ ("gr8"); \ +__asm__ __volatile__ ("tra gr0,gr0" \ + : "=r" (__sc0) \ + : "r" (__scnum)); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) \ +{ \ +register unsigned long __scnum __asm__ ("gr7") = (__NR_##name); \ +register unsigned long __sc0 __asm__ ("gr8") = (unsigned long) arg1; \ +__asm__ __volatile__ ("tra gr0,gr0" \ + : "+r" (__sc0) \ + : "r" (__scnum)); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1,type2 arg2) \ +{ \ +register unsigned long __scnum __asm__ ("gr7") = (__NR_##name); \ +register unsigned long __sc0 __asm__ ("gr8") = (unsigned long) arg1; \ +register unsigned long __sc1 __asm__ ("gr9") = (unsigned long) arg2; \ +__asm__ __volatile__ ("tra gr0,gr0" \ + : "+r" (__sc0) \ + : "r" (__scnum), "r" (__sc1)); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1,type2 arg2,type3 arg3) \ +{ \ +register unsigned long __scnum __asm__ ("gr7") = (__NR_##name); \ +register unsigned long __sc0 __asm__ ("gr8") = (unsigned long) arg1; \ +register unsigned long __sc1 __asm__ ("gr9") = (unsigned long) arg2; \ +register unsigned long __sc2 __asm__ ("gr10") = (unsigned long) arg3; \ +__asm__ __volatile__ ("tra gr0,gr0" \ + : "+r" (__sc0) \ + : "r" (__scnum), "r" (__sc1), "r" (__sc2)); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ +register unsigned long __scnum __asm__ ("gr7") = (__NR_##name); \ +register unsigned long __sc0 __asm__ ("gr8") = (unsigned long) arg1; \ +register unsigned long __sc1 __asm__ ("gr9") = (unsigned long) arg2; \ +register unsigned long __sc2 __asm__ ("gr10") = (unsigned long) arg3; \ +register unsigned long __sc3 __asm__ ("gr11") = (unsigned long) arg4; \ +__asm__ __volatile__ ("tra gr0,gr0" \ + : "+r" (__sc0) \ + : "r" (__scnum), "r" (__sc1), "r" (__sc2), "r" (__sc3)); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ +{ \ +register unsigned long __scnum __asm__ ("gr7") = (__NR_##name); \ +register unsigned long __sc0 __asm__ ("gr8") = (unsigned long) arg1; \ +register unsigned long __sc1 __asm__ ("gr9") = (unsigned long) arg2; \ +register unsigned long __sc2 __asm__ ("gr10") = (unsigned long) arg3; \ +register unsigned long __sc3 __asm__ ("gr11") = (unsigned long) arg4; \ +register unsigned long __sc4 __asm__ ("gr12") = (unsigned long) arg5; \ +__asm__ __volatile__ ("tra gr0,gr0" \ + : "+r" (__sc0) \ + : "r" (__scnum), "r" (__sc1), "r" (__sc2), \ + "r" (__sc3), "r" (__sc4)); \ +__syscall_return(type,__sc0); \ +} + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5, type6, arg6) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \ +{ \ +register unsigned long __scnum __asm__ ("gr7") = (__NR_##name); \ +register unsigned long __sc0 __asm__ ("gr8") = (unsigned long) arg1; \ +register unsigned long __sc1 __asm__ ("gr9") = (unsigned long) arg2; \ +register unsigned long __sc2 __asm__ ("gr10") = (unsigned long) arg3; \ +register unsigned long __sc3 __asm__ ("gr11") = (unsigned long) arg4; \ +register unsigned long __sc4 __asm__ ("gr12") = (unsigned long) arg5; \ +register unsigned long __sc5 __asm__ ("gr13") = (unsigned long) arg6; \ +__asm__ __volatile__ ("tra gr0,gr0" \ + : "+r" (__sc0) \ + : "r" (__scnum), "r" (__sc1), "r" (__sc2), \ + "r" (__sc3), "r" (__sc4), "r" (__sc5)); \ +__syscall_return(type,__sc0); \ +} + +#endif /* __ASSEMBLER__ */ +#endif /* _BITS_SYSCALLS_H */ diff --git a/libc/sysdeps/linux/frv/bits/wordsize.h b/libc/sysdeps/linux/frv/bits/wordsize.h new file mode 100644 index 000000000..ba643b60a --- /dev/null +++ b/libc/sysdeps/linux/frv/bits/wordsize.h @@ -0,0 +1,19 @@ +/* Copyright (C) 1999 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. */ + +#define __WORDSIZE 32 diff --git a/libc/sysdeps/linux/frv/brk.c b/libc/sysdeps/linux/frv/brk.c new file mode 100644 index 000000000..4f97fb084 --- /dev/null +++ b/libc/sysdeps/linux/frv/brk.c @@ -0,0 +1,22 @@ +/* From libc-5.3.12 */ + +#include <errno.h> +#include <unistd.h> +#include <sys/syscall.h> + +extern void * ___brk_addr; + +extern int __init_brk (void); +extern void *_brk(void *ptr); + +int brk(void * end_data_seg) +{ + if (__init_brk () == 0) + { + ___brk_addr = _brk(end_data_seg); + if (___brk_addr == end_data_seg) + return 0; + __set_errno(ENOMEM); + } + return -1; +} diff --git a/libc/sysdeps/linux/frv/clone.S b/libc/sysdeps/linux/frv/clone.S new file mode 100644 index 000000000..2e3c6b742 --- /dev/null +++ b/libc/sysdeps/linux/frv/clone.S @@ -0,0 +1,83 @@ +/* Copyright (C) 2003 Free Software Foudnation, Inc. + This file is part of the GNU C Library. + Contributed by Alexandre Oliva <aoliva@redhat.com>, 2003. + + 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. */ + +/* clone() is even more special than fork() as it mucks with stacks + and invokes a function in the right context after its all over. */ + +#include <asm/unistd.h> +#define _ERRNO_H 1 +#include <bits/errno.h> + + .text + .globl __clone + .type __clone,@function +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg) */ +__clone: + /* Sanity check arguments. */ + cmp.p gr8, gr0, icc0 + cmp gr9, gr0, icc1 + mov.p gr8, gr4 + beq icc0, #0, .Lerror + mov.p gr11, gr5 + beq icc1, #0, .Lerror + + mov.p gr10, gr8 + setlos #__NR_clone, gr7 + tra gr0,gr0 + + cmp gr8, gr0, icc0 + bgtlr icc0, #1 + beq icc0, #0, .Lthread_start + +.Lsys_error: + sethi.p #gotofffuncdeschi(__syscall_error), gr14 + setlo #gotofffuncdesclo(__syscall_error), gr14 + ldd @(gr14, gr15), gr14 + jmpl @(gr14, gr0) + +.Lerror: + setlos.p #-EINVAL, gr7 + bra .Lsys_error + +############################################################################### +# +# come here as the new thread [GR4 is fn, GR5 is arg] +# +############################################################################### +.Lthread_start: + /* Save the PIC register. */ + mov gr15, gr17 + + /* Call the user's function. */ + ldd.p @(gr4, gr0), gr14 + mov gr5, gr8 + calll @(gr14, gr0) + + /* Call _exit, rather simply inlining the syscall, such that + breakpoints work.*/ + + mov.p gr17, gr15 + call _exit + + /* Should never get here. */ + jmpl @(gr0, gr0) + .size __clone,.-__clone + +.weak clone + clone = __clone diff --git a/libc/sysdeps/linux/frv/crt0.S b/libc/sysdeps/linux/frv/crt0.S new file mode 100644 index 000000000..8a425158f --- /dev/null +++ b/libc/sysdeps/linux/frv/crt0.S @@ -0,0 +1,110 @@ +/* Copyright (C) 1991, 1992, 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 +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 +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. */ + + +/* Based on ../i386/crt0.S and newlib's libgloss/frv/crt0.S */ + +/* + When we enter this piece of code, the program stack looks like this: + argc argument counter (integer) + argv[0] program name (pointer) + argv[1...N] program args (pointers) + argv[argc-1] end of args (integer) + NULL + env[0...N] environment variables (pointers) + NULL + + Also, GR16 holds a pointer to a memory map. */ + +#include <features.h> + + .text + .global _start + .type _start,%function +#if defined L_crt0 || defined L_Scrt0 || ! defined __UCLIBC_CTOR_DTOR__ + .type __uClibc_main,%function +#else + .weak _init + .weak _fini + .type __uClibc_start_main,%function +#endif +/* Stick in a dummy reference to main(), so that if an application + * is linking when the main() function is in a static library (.a) + * we can be sure that main() actually gets linked in */ + .type main,%function +_start: + /* At program start-up, gr16 contains a pointer to a memory + map, that we use to relocate addresses. */ + call .Lcall +.Lcall: + movsg lr, gr4 + sethi.p #gprelhi(.Lcall), gr5 + setlo #gprello(.Lcall), gr5 + sub.p gr4, gr5, gr4 + /* gr4 now holds the _gp address. */ + + mov gr16, gr8 + sethi.p #gprelhi(__ROFIXUP_LIST__), gr9 + sethi #gprelhi(__ROFIXUP_END__), gr10 + setlo.p #gprello(__ROFIXUP_LIST__), gr9 + setlo #gprello(__ROFIXUP_END__), gr10 + add.p gr9, gr4, gr9 + add gr10, gr4, gr10 + call __self_reloc + mov.p gr8, gr17 + mov gr8, gr15 + /* gr17 now holds the self-relocated _GLOBAL_OFFSET_TABLE_ + address, because the linker added its unrelocated address as + the last entry in the ROFIXUP list, and __self_reloc returns + the last entry, relocated. */ + + /* Prepare arguments for uClibc main. */ + ld @(sp, gr0), gr8 + slli gr8, #2, gr10 + add sp, gr10, gr10 + addi.p sp, #4, gr9 + addi gr10, #8, gr10 + + /* Set up an invalid (NULL return address, NULL frame pointer) + callers stack frame so anybody unrolling the stack knows where + to stop */ + mov gr0, fp + movgs gr0, lr + +#if (defined L_crt1 || defined L_gcrt1 || defined L_Scrt1) && defined __UCLIBC_CTOR_DTOR__ + /* Pass .init and .fini arguments to __uClibc_start_main(). */ + sethi.p #gotfuncdeschi(_init), gr11 + sethi #gotfuncdeschi(_fini), gr12 + setlo.p #gotfuncdesclo(_init), gr11 + setlo #gotfuncdesclo(_fini), gr12 + ld.p @(gr11, gr17), gr11 + mov gr17, gr15 + ld.p @(gr12, gr17), gr12 + call __uClibc_start_main +#else + mov.p gr17, gr15 + call __uClibc_main +#endif + + /* Crash if somehow `exit' returns anyways. */ + jmpl @(gr0,gr0) +.size _start,.-_start + +#if defined L_gcrt1 && defined __UCLIBC_PROFILING__ +# include "./gmon-start.S" +#endif diff --git a/libc/sysdeps/linux/frv/crti.S b/libc/sysdeps/linux/frv/crti.S new file mode 100644 index 000000000..715ce4a89 --- /dev/null +++ b/libc/sysdeps/linux/frv/crti.S @@ -0,0 +1,41 @@ +/* Copyright (C) 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 +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 +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. */ + + .section .init,"x" + .p2align 2 + .globl _init + .type _init, @function +_init: + addi sp,#-16,sp + st.p fp, @(sp,gr0) + mov sp, fp + movsg lr, gr5 + sti gr15, @(fp,4) + sti gr5, @(fp,8) + + .section .fini,"x" + .p2align 2 + .globl _fini + .type _fini, @function +_fini: + addi sp,#-16,sp + st.p fp, @(sp,gr0) + mov sp, fp + movsg lr, gr5 + sti gr15, @(fp,4) + sti gr5, @(fp,8) diff --git a/libc/sysdeps/linux/frv/crtn.S b/libc/sysdeps/linux/frv/crtn.S new file mode 100644 index 000000000..b495bbeb2 --- /dev/null +++ b/libc/sysdeps/linux/frv/crtn.S @@ -0,0 +1,35 @@ +/* Copyright (C) 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 +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 +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. */ + + .section .init,"x" + .globl _init + .type _init, @function + ldi @(fp,8), gr5 + ld @(sp,gr0), fp + addi sp,#16,sp + jmpl @(gr5,gr0) + .size _init, .-_init + + .section .fini,"x" + .globl _fini + .type _fini, @function + ldi @(fp,8), gr5 + ld @(sp,gr0), fp + addi sp,#16,sp + jmpl @(gr5,gr0) + .size _fini, .-_fini diff --git a/libc/sysdeps/linux/frv/crtreloc.c b/libc/sysdeps/linux/frv/crtreloc.c new file mode 100644 index 000000000..38af68c7b --- /dev/null +++ b/libc/sysdeps/linux/frv/crtreloc.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2003 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. + +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. */ + +#define _GNU_SOURCE +#include <link.h> + +#include <sys/types.h> + +#include <elf.h> +#include <bits/elf-fdpic.h> + +/* This file is to be compiled into crt object files, to enable + executables to easily self-relocate. */ + +#define hidden __attribute__((__visibility__("hidden"))) + +/* Compute the runtime address of pointer in the range [p,e), and then + map the pointer pointed by it. */ +inline static 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; + if ((long)ptr & 3) + __builtin_memcpy(&pt, ptr, sizeof(pt)); + else + pt = *(void**)ptr; + pt = __reloc_pointer (pt, map); + if ((long)ptr & 3) + __builtin_memcpy(ptr, &pt, sizeof(pt)); + else + *(void**)ptr = 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* 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). */ +inline static 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 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* 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/frv/dl-iterate-phdr.c b/libc/sysdeps/linux/frv/dl-iterate-phdr.c new file mode 100644 index 000000000..ebb3b9c4a --- /dev/null +++ b/libc/sysdeps/linux/frv/dl-iterate-phdr.c @@ -0,0 +1,43 @@ +/* Copyright 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 +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 +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. */ + +#define _GNU_SOURCE +#include <link.h> + +extern int __attribute__((__weak__)) +__dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, + size_t size, void *data), + void *data); + +/* Define it as a pointer, such that we get a pointer to the global + function descriptor, that won't be optimized away by the + linker. */ +static int (*ptr) (int (*callback) (struct dl_phdr_info *info, + size_t size, void *data), + void *data) = __dl_iterate_phdr; + +int +dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, + size_t size, void *data), + void *data) +{ + if (ptr) + return ptr (callback, data); + + return 0; +} diff --git a/libc/sysdeps/linux/frv/sbrk.c b/libc/sysdeps/linux/frv/sbrk.c new file mode 100644 index 000000000..c39d60063 --- /dev/null +++ b/libc/sysdeps/linux/frv/sbrk.c @@ -0,0 +1,25 @@ +/* From libc-5.3.12 */ + +#include <errno.h> +#include <unistd.h> +#include <sys/syscall.h> + +extern void * ___brk_addr; + +extern int __init_brk (void); +extern void *_brk(void *ptr); + +void * +sbrk(intptr_t increment) +{ + if (__init_brk () == 0) + { + char * tmp = (char*)___brk_addr+increment; + ___brk_addr = _brk(tmp); + if (___brk_addr == tmp) + return tmp-increment; + __set_errno(ENOMEM); + return ((void *) -1); + } + return ((void *) -1); +} diff --git a/libc/sysdeps/linux/frv/setjmp.S b/libc/sysdeps/linux/frv/setjmp.S new file mode 100644 index 000000000..455e61178 --- /dev/null +++ b/libc/sysdeps/linux/frv/setjmp.S @@ -0,0 +1,95 @@ +#include <features.h> +#define _SETJMP_H +#define _ASM +#include <bits/setjmp.h> + + .text + +/* This just does a tail-call to `__sigsetjmp (ARG, 0)'. + We cannot do it in C because it must be a tail-call, so frame-unwinding + in setjmp doesn't clobber the state restored by longjmp. */ + + .global _setjmp + .type _setjmp,@function +_setjmp: + setlos #0, gr9 + bra .Lsigsetjmp_intern + .size _setjmp,.-_setjmp + +/* This just does a tail-call to `__sigsetjmp (ARG, 1)'. + We cannot do it in C because it must be a tail-call, so frame-unwinding + in setjmp doesn't clobber the state restored by longjmp. */ + + .align 4 + .type setjmp,@function + .globl setjmp +setjmp: + setlos #1, gr9 + bra .Lsigsetjmp_intern + .size setjmp,.-setjmp + +# setjmp/longjmp for Frv. The jmpbuf looks like this: +# +# Register jmpbuf offset +# R16-R31 0x0-0x03c +# R48-R63 0x40-0x7c +# FR16-FR31 0x80-0xbc +# FR48-FR63 0xc0-0xfc +# LR 0x100 +# SP 0x104 +# FP 0x108 + + .global __sigsetjmp + .type __sigsetjmp,@function +__sigsetjmp: +.Lsigsetjmp_intern: + stdi gr16, @(gr8,0) + stdi gr18, @(gr8,8) + stdi gr20, @(gr8,16) + stdi gr22, @(gr8,24) + stdi gr24, @(gr8,32) + stdi gr26, @(gr8,40) + stdi gr28, @(gr8,48) + stdi gr30, @(gr8,56) +#if __FRV_GPR__ != 32 + stdi gr48, @(gr8,64) + stdi gr50, @(gr8,72) + stdi gr52, @(gr8,80) + stdi gr54, @(gr8,88) + stdi gr56, @(gr8,96) + stdi gr58, @(gr8,104) + stdi gr60, @(gr8,112) + stdi gr62, @(gr8,120) +#endif + +#if __FRV_FPR__ != 0 + stdfi fr16, @(gr8,128) + stdfi fr18, @(gr8,136) + stdfi fr20, @(gr8,144) + stdfi fr22, @(gr8,152) + stdfi fr24, @(gr8,160) + stdfi fr26, @(gr8,168) + stdfi fr28, @(gr8,176) + stdfi fr30, @(gr8,184) +#if __FRV_FPR__ != 32 + stdfi fr48, @(gr8,192) + stdfi fr50, @(gr8,200) + stdfi fr52, @(gr8,208) + stdfi fr54, @(gr8,216) + stdfi fr56, @(gr8,224) + stdfi fr58, @(gr8,232) + stdfi fr60, @(gr8,240) + stdfi fr62, @(gr8,248) +#endif +#endif + + movsg lr, gr4 + sti gr4, @(gr8,256) + sti sp, @(gr8,260) + sti fp, @(gr8,264) + + sethi.p #gotofffuncdeschi(__sigjmp_save), gr4 + setlo #gotofffuncdesclo(__sigjmp_save), gr4 + ldd @(gr15, gr4), gr14 + jmpl @(gr14, gr0) + .size __sigsetjmp,.-__sigsetjmp diff --git a/libc/sysdeps/linux/frv/sys/procfs.h b/libc/sysdeps/linux/frv/sys/procfs.h new file mode 100644 index 000000000..f07523342 --- /dev/null +++ b/libc/sysdeps/linux/frv/sys/procfs.h @@ -0,0 +1,125 @@ +/* Copyright (C) 1996, 1997, 1999, 2000, 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 + 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_PROCFS_H +#define _SYS_PROCFS_H 1 + +/* This is somewhat modelled after the file of the same name on SVR4 + systems. It provides a definition of the core file format for ELF + used on Linux. It doesn't have anything to do with the /proc file + system, even though Linux has one. + + Anyway, the whole purpose of this file is for GDB and GDB only. + Don't read too much into it. Don't use it for anything other than + GDB unless you know what you are doing. */ + +#include <features.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/user.h> + +__BEGIN_DECLS + +/* Type for a general-purpose register. */ +typedef unsigned long elf_greg_t; + +/* And the whole bunch of them. We could have used `struct + user_regs_struct' directly in the typedef, but tradition says that + the register set is an array, which does have some peculiar + semantics, so leave it that way. */ +#define ELF_NGREG (sizeof (struct user_int_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +/* Register set for the floating-point registers. */ +typedef struct user_fpmedia_regs elf_fpregset_t; + +/* Signal info. */ +struct elf_siginfo + { + int si_signo; /* Signal number. */ + int si_code; /* Extra code. */ + int si_errno; /* Errno. */ + }; + + +/* Definitions to generate Intel SVR4-like core files. These mostly + have the same names as the SVR4 types with "elf_" tacked on the + front to prevent clashes with Linux definitions, and the typedef + forms have been avoided. This is mostly like the SVR4 structure, + but more Linuxy, with things that Linux does not support and which + GDB doesn't really use excluded. */ + +struct elf_prstatus + { + struct elf_siginfo pr_info; /* Info associated with signal. */ + short int pr_cursig; /* Current signal. */ + unsigned long int pr_sigpend; /* Set of pending signals. */ + unsigned long int pr_sighold; /* Set of held signals. */ + __pid_t pr_pid; + __pid_t pr_ppid; + __pid_t pr_pgrp; + __pid_t pr_sid; + struct timeval pr_utime; /* User time. */ + struct timeval pr_stime; /* System time. */ + struct timeval pr_cutime; /* Cumulative user time. */ + struct timeval pr_cstime; /* Cumulative system time. */ + elf_gregset_t pr_reg; /* GP registers. */ + int pr_fpvalid; /* True if math copro being used. */ + }; + + +#define ELF_PRARGSZ (80) /* Number of chars for args. */ + +struct elf_prpsinfo + { + char pr_state; /* Numeric process state. */ + char pr_sname; /* Char for pr_state. */ + char pr_zomb; /* Zombie. */ + char pr_nice; /* Nice val. */ + unsigned long int pr_flag; /* Flags. */ + unsigned short int pr_uid; + unsigned short int pr_gid; + int pr_pid, pr_ppid, pr_pgrp, pr_sid; + /* Lots missing */ + char pr_fname[16]; /* Filename of executable. */ + char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */ + }; + + +/* The rest of this file provides the types for emulation of the + Solaris <proc_service.h> interfaces that should be implemented by + users of libthread_db. */ + +/* Addresses. */ +typedef void *psaddr_t; + +/* Register sets. Linux has different names. */ +typedef elf_gregset_t prgregset_t; +typedef elf_fpregset_t prfpregset_t; + +/* We don't have any differences between processes and threads, + therefore have only one PID type. */ +typedef __pid_t lwpid_t; + +/* Process status and info. In the end we do provide typedefs for them. */ +typedef struct elf_prstatus prstatus_t; +typedef struct elf_prpsinfo prpsinfo_t; + +__END_DECLS + +#endif /* sys/procfs.h */ diff --git a/libc/sysdeps/linux/frv/sys/ptrace.h b/libc/sysdeps/linux/frv/sys/ptrace.h new file mode 100644 index 000000000..6b0eca7b0 --- /dev/null +++ b/libc/sysdeps/linux/frv/sys/ptrace.h @@ -0,0 +1,139 @@ +/* `ptrace' debugger support interface. FRV-Linux version. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 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. + + 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 +}; + +#define PTRACE_GETFDPIC_EXEC ((void*)0) /* [addr] request the executable loadmap */ +#define PTRACE_GETFDPIC_INTERP ((void*)1) /* [addr] request the interpreter loadmap */ + +/* 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/frv/sys/ucontext.h b/libc/sysdeps/linux/frv/sys/ucontext.h new file mode 100644 index 000000000..2385a072e --- /dev/null +++ b/libc/sysdeps/linux/frv/sys/ucontext.h @@ -0,0 +1,451 @@ +/* Copyright (C) 1999, 2000, 2001, 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 + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _SYS_UCONTEXT_H +#define _SYS_UCONTEXT_H 1 + +#include <features.h> +#include <signal.h> + +/* We need the signal context definitions even if they are not used + included in <signal.h>. */ +#include <bits/sigcontext.h> + + +typedef unsigned long greg_t; + +/* Number of general registers. */ +#define NGREG (10+2+64) + +/* Container for all general registers. */ +typedef greg_t gregset_t[NGREG]; + +#ifdef __USE_GNU +/* Number of each register is the `gregset_t' array. */ +enum +{ + PSR = 0, +#define PSR PSR + ISR = 1, +#define ISR ISR + CCR = 2, +#define CCR CCR + CCCR = 3, +#define CCCR CCCR + LR = 4, +#define LR LR + LCR = 5, +#define LCR LCR + PC = 6, +#define PC PC + __STATUS = 7, +#define __STATUS __STATUS + SYSCALLNO = 8, +#define SYSCALLNO SYSCALLNO + ORIG_GR8 = 9, +#define ORIG_GR8 ORIG_GR8 + GNER0 = 10, +#define GNER0 GNER0 + GNER1 = 11, +#define GNER1 GNER1 + GR0 = 12, +#define GR0 GR0 + GR1 = 13, +#define GR1 GR1 + GR2 = 14, +#define GR2 GR2 + GR3 = 15, +#define GR3 GR3 + GR4 = 16, +#define GR4 GR4 + GR5 = 17, +#define GR5 GR5 + GR6 = 18, +#define GR6 GR6 + GR7 = 19, +#define GR7 GR7 + GR8 = 20, +#define GR8 GR8 + GR9 = 21, +#define GR9 GR9 + GR10 = 22, +#define GR10 GR10 + GR11 = 23, +#define GR11 GR11 + GR12 = 24, +#define GR12 GR12 + GR13 = 25, +#define GR13 GR13 + GR14 = 26, +#define GR14 GR14 + GR15 = 27, +#define GR15 GR15 + GR16 = 28, +#define GR16 GR16 + GR17 = 29, +#define GR17 GR17 + GR18 = 30, +#define GR18 GR18 + GR19 = 31, +#define GR19 GR19 + GR20 = 32, +#define GR20 GR20 + GR21 = 33, +#define GR21 GR21 + GR22 = 34, +#define GR22 GR22 + GR23 = 35, +#define GR23 GR23 + GR24 = 36, +#define GR24 GR24 + GR25 = 37, +#define GR25 GR25 + GR26 = 38, +#define GR26 GR26 + GR27 = 39, +#define GR27 GR27 + GR28 = 40, +#define GR28 GR28 + GR29 = 41, +#define GR29 GR29 + GR30 = 42, +#define GR30 GR30 + GR31 = 43, +#define GR31 GR31 + GR32 = 44, +#define GR32 GR32 + GR33 = 45, +#define GR33 GR33 + GR34 = 46, +#define GR34 GR34 + GR35 = 47, +#define GR35 GR35 + GR36 = 48, +#define GR36 GR36 + GR37 = 49, +#define GR37 GR37 + GR38 = 50, +#define GR38 GR38 + GR39 = 51, +#define GR39 GR39 + GR40 = 52, +#define GR40 GR40 + GR41 = 53, +#define GR41 GR41 + GR42 = 54, +#define GR42 GR42 + GR43 = 55, +#define GR43 GR43 + GR44 = 56, +#define GR44 GR44 + GR45 = 57, +#define GR45 GR45 + GR46 = 58, +#define GR46 GR46 + GR47 = 59, +#define GR47 GR47 + GR48 = 60, +#define GR48 GR48 + GR49 = 61, +#define GR49 GR49 + GR50 = 62, +#define GR50 GR50 + GR51 = 63, +#define GR51 GR51 + GR52 = 64, +#define GR52 GR52 + GR53 = 65, +#define GR53 GR53 + GR54 = 66, +#define GR54 GR54 + GR55 = 67, +#define GR55 GR55 + GR56 = 68, +#define GR56 GR56 + GR57 = 69, +#define GR57 GR57 + GR58 = 70, +#define GR58 GR58 + GR59 = 71, +#define GR59 GR59 + GR60 = 72, +#define GR60 GR60 + GR61 = 73, +#define GR61 GR61 + GR62 = 74, +#define GR62 GR62 + GR63 = 75, +#define GR63 GR63 +}; +#endif + +typedef unsigned long freg_t; + +/* Number of FPU registers. */ +#define NFPREG (64+2+2+8+2+1) + +#ifdef __USE_GNU +/* Number of each register is the `gregset_t' array. */ +enum +{ + FR0 = 0, +#define FR0 FR0 + FR1 = 1, +#define FR1 FR1 + FR2 = 2, +#define FR2 FR2 + FR3 = 3, +#define FR3 FR3 + FR4 = 4, +#define FR4 FR4 + FR5 = 5, +#define FR5 FR5 + FR6 = 6, +#define FR6 FR6 + FR7 = 7, +#define FR7 FR7 + FR8 = 8, +#define FR8 FR8 + FR9 = 9, +#define FR9 FR9 + FR10 = 10, +#define FR10 FR10 + FR11 = 11, +#define FR11 FR11 + FR12 = 12, +#define FR12 FR12 + FR13 = 13, +#define FR13 FR13 + FR14 = 14, +#define FR14 FR14 + FR15 = 15, +#define FR15 FR15 + FR16 = 16, +#define FR16 FR16 + FR17 = 17, +#define FR17 FR17 + FR18 = 18, +#define FR18 FR18 + FR19 = 19, +#define FR19 FR19 + FR20 = 20, +#define FR20 FR20 + FR21 = 21, +#define FR21 FR21 + FR22 = 22, +#define FR22 FR22 + FR23 = 23, +#define FR23 FR23 + FR24 = 24, +#define FR24 FR24 + FR25 = 25, +#define FR25 FR25 + FR26 = 26, +#define FR26 FR26 + FR27 = 27, +#define FR27 FR27 + FR28 = 28, +#define FR28 FR28 + FR29 = 29, +#define FR29 FR29 + FR30 = 30, +#define FR30 FR30 + FR31 = 31, +#define FR31 FR31 + FR32 = 32, +#define FR32 FR32 + FR33 = 33, +#define FR33 FR33 + FR34 = 34, +#define FR34 FR34 + FR35 = 35, +#define FR35 FR35 + FR36 = 36, +#define FR36 FR36 + FR37 = 37, +#define FR37 FR37 + FR38 = 38, +#define FR38 FR38 + FR39 = 39, +#define FR39 FR39 + FR40 = 40, +#define FR40 FR40 + FR41 = 41, +#define FR41 FR41 + FR42 = 42, +#define FR42 FR42 + FR43 = 43, +#define FR43 FR43 + FR44 = 44, +#define FR44 FR44 + FR45 = 45, +#define FR45 FR45 + FR46 = 46, +#define FR46 FR46 + FR47 = 47, +#define FR47 FR47 + FR48 = 48, +#define FR48 FR48 + FR49 = 49, +#define FR49 FR49 + FR50 = 50, +#define FR50 FR50 + FR51 = 51, +#define FR51 FR51 + FR52 = 52, +#define FR52 FR52 + FR53 = 53, +#define FR53 FR53 + FR54 = 54, +#define FR54 FR54 + FR55 = 55, +#define FR55 FR55 + FR56 = 56, +#define FR56 FR56 + FR57 = 57, +#define FR57 FR57 + FR58 = 58, +#define FR58 FR58 + FR59 = 59, +#define FR59 FR59 + FR60 = 60, +#define FR60 FR60 + FR61 = 61, +#define FR61 FR61 + FR62 = 62, +#define FR62 FR62 + FR63 = 63, +#define FR63 FR63 + FNER0 = 64, +#define FNER0 FNER0 + FNER1 = 65, +#define FNER1 FNER1 + MSR0 = 66, +#define MSR0 MSR0 + MSR1 = 67, +#define MSR1 MSR1 + ACC0 = 68, +#define ACC0 ACC0 + ACC1 = 69, +#define ACC1 ACC1 + ACC2 = 70, +#define ACC2 ACC2 + ACC3 = 71, +#define ACC3 ACC3 + ACC4 = 72, +#define ACC4 ACC4 + ACC5 = 73, +#define ACC5 ACC5 + ACC6 = 74, +#define ACC6 ACC6 + ACC7 = 75, +#define ACC7 ACC7 + ACCG0123 = 76, +#define ACCG0123 ACCG0123 + ACCG4567 = 77, +#define ACCG4567 ACCG4567 + FSR0 = 78, +#define FSR0 FSR0 +}; +#endif + +/* Structure to describe FPU registers. */ +typedef freg_t fpregset_t[NFPREG]; + +/* Context to describe whole processor state. */ +typedef struct + { + gregset_t gregs; + fpregset_t fpregs; + void *extension; + unsigned long sc_oldmask; /* old sigmask */ + } __attribute__((aligned(8))) mcontext_t; + +#ifdef __USE_GNU +struct kernel_user_int_regs +{ + /* integer registers + * - up to gr[31] mirror pt_regs in the kernel + */ + unsigned long psr; /* Processor Status Register */ + unsigned long isr; /* Integer Status Register */ + unsigned long ccr; /* Condition Code Register */ + unsigned long cccr; /* Condition Code for Conditional Insns Register */ + unsigned long lr; /* Link Register */ + unsigned long lcr; /* Loop Count Register */ + unsigned long pc; /* Program Counter Register */ + unsigned long __status; /* exception status */ + unsigned long syscallno; /* syscall number or -1 */ + unsigned long orig_gr8; /* original syscall arg #1 */ + unsigned long gner[2]; + + union { + unsigned long tbr; + unsigned long gr[64]; + }; +}; + +struct kernel_user_fpmedia_regs +{ + /* FP/Media registers */ + unsigned long fr[64]; + unsigned long fner[2]; + unsigned long msr[2]; + unsigned long acc[8]; + unsigned char accg[8]; + unsigned long fsr[1]; +}; + +struct kernel_user_context +{ + struct kernel_user_int_regs i; + struct kernel_user_fpmedia_regs f; + + /* we provide a context extension so that we can save the regs for CPUs that + * implement many more of Fujitsu's lavish register spec + */ + void *extension; + + /* This is not part of the kernel's struct user_context, but + rather of the enclosing struct sigcontext, but we add it + here to parallel mcontext_t, just for completeness. */ + unsigned long sc_oldmask; /* old sigmask */ +} __attribute__((aligned(8))); + +/* This union enables alias-safe casts from mcontext_t* to the union + type, that can then be dereferenced as_aliases. */ +union kmcontext_t +{ + mcontext_t as_regsets; + /* as_aliases is actually missing sc_oldmask, that is present in + mcontext_t. */ + struct kernel_user_context as_aliases; +}; +#endif + +/* Userlevel context. */ +typedef struct ucontext + { + unsigned long int uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + __sigset_t uc_sigmask; + } ucontext_t; + +#endif /* sys/ucontext.h */ diff --git a/libc/sysdeps/linux/frv/sysdep.c b/libc/sysdeps/linux/frv/sysdep.c new file mode 100644 index 000000000..17260f72f --- /dev/null +++ b/libc/sysdeps/linux/frv/sysdep.c @@ -0,0 +1,27 @@ +/* Copyright (C) 1997, 1998 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. */ + +#include <errno.h> + +/* This routine is jumped to by all the syscall handlers, to stash + an error number into errno. */ +int __syscall_error (int err_no) +{ + __set_errno (err_no); + return -1; +} diff --git a/libc/sysdeps/linux/frv/vfork.S b/libc/sysdeps/linux/frv/vfork.S new file mode 100644 index 000000000..2f97b2a47 --- /dev/null +++ b/libc/sysdeps/linux/frv/vfork.S @@ -0,0 +1,44 @@ +/* Copyright (C) 2003 Free Software Foudnation, Inc. + This file is part of the GNU C Library. + Contributed by David Howells <dhowells@redhat.com>, 2003. + + 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. */ + +#include <asm/unistd.h> +#define _ERRNO_H 1 +#include <bits/errno.h> + + .text + .globl __libc_vfork + .type __libc_vfork,@function +/* int vfork(void) */ +__libc_vfork: + setlos #__NR_vfork, gr7 + tira gr0, #0 + + cmp gr8, gr0, icc0 + bplr icc0, #2 + + sethi.p #gotofffuncdeschi(__syscall_error), gr14 + setlo #gotofffuncdesclo(__syscall_error), gr14 + ldd @(gr14, gr15), gr14 + jmpl @(gr14, gr0) + + .size vfork,.-vfork + +.weak vfork +.global vfork +.set vfork, __libc_vfork diff --git a/libpthread/linuxthreads/sysdeps/frv/pt-machine.h b/libpthread/linuxthreads/sysdeps/frv/pt-machine.h new file mode 100644 index 000000000..067928062 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/frv/pt-machine.h @@ -0,0 +1,48 @@ +/* Machine-dependent pthreads configuration and inline functions. + ARM version. + Copyright (C) 1997, 1998, 2000, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Alexandre Oliva <aoliva@redhat.com> + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline +#endif + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +extern long int testandset (int *spinlock); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + register long int ret = 1; + + __asm__ __volatile__("swap%I1\t%M1,%0" + : "+r"(ret), "+m"(*spinlock)); + + return ret; +} + +#endif /* pt-machine.h */ |