diff options
Diffstat (limited to 'cpukit/libdl')
78 files changed, 14343 insertions, 0 deletions
diff --git a/cpukit/libdl/Makefile.am b/cpukit/libdl/Makefile.am new file mode 100644 index 0000000000..11f1478522 --- /dev/null +++ b/cpukit/libdl/Makefile.am @@ -0,0 +1,36 @@ +if LIBDL + +include $(top_srcdir)/automake/compile.am + +noinst_LIBRARIES = libdl.a +libdl_a_SOURCES = \ + dlfcn-shell.c \ + dlfcn.c \ + fastlz.c \ + rap-shell.c \ + rap.c \ + rtl.c \ + rtl-alloc-heap.c \ + rtl-allocator.c \ + rtl-chain-iterator.c \ + rtl-debugger.c \ + rtl-elf.c \ + rtl-error.c \ + rtl-find-file.c \ + rtl-obj-cache.c \ + rtl-obj-comp.c \ + rtl-obj.c \ + rtl-rap.c \ + rtl-shell.c \ + rtl-string.c \ + rtl-sym.c \ + rtl-trace.c \ + rtl-unresolved.c + +libdl_a_SOURCES += rtl-mdreloc-@RTEMS_CPU@.c +libdl_a_CPPFLAGS = $(AM_CPPFLAGS) -DRTEMS_RTL_RAP_LOADER=1 -DRTEMS_RTL_ELF_LOADER=1 + +include $(srcdir)/preinstall.am +include $(top_srcdir)/automake/local.am + +endif diff --git a/cpukit/libdl/dlfcn-shell.c b/cpukit/libdl/dlfcn-shell.c new file mode 100644 index 0000000000..5655ab1455 --- /dev/null +++ b/cpukit/libdl/dlfcn-shell.c @@ -0,0 +1,117 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor Dynamic Loading API Shell Support. + * + * Shell command wrappers for the Dynamic Loading API. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <dlfcn.h> +#include <rtems/rtl/dlfcn-shell.h> + +static void* +convert_ascii_to_voidp (const char* arg) +{ + if (strcmp (arg, "base") == 0) + return RTLD_DEFAULT; + return (void*) strtoul (arg, NULL, 16); +} + +int +shell_dlopen (int argc, char* argv[]) +{ + int arg; + for (arg = 1; arg < argc; arg++) + { + void* handle = dlopen (argv[arg], RTLD_NOW | RTLD_GLOBAL); + if (handle) + { + int unresolved; + char* message = "loaded"; + if (dlinfo (handle, RTLD_DI_UNRESOLVED, &unresolved) < 0) + message = "dlinfo error checking unresolved status"; + else if (unresolved) + message = "has unresolved externals"; + printf ("handle: %p %s\n", handle, message); + } + else + printf ("error: %s\n", dlerror ()); + } + return 0; +} + +int +shell_dlclose (int argc, char* argv[]) +{ + return 0; +} + +static bool +lookup_dlsym (void** value, int argc, char* argv[]) +{ + if (argc >= 3) + { + void* handle = convert_ascii_to_voidp (argv[1]); + if (handle) + { + *value = dlsym (handle, argv[2]); + if (*value) + return true; + else + printf ("error: invalid handle or symbol\n"); + } + else + printf ("error: invalid handle"); + } + else + printf ("error: requires handle and symbol name\n"); + return false; +} + +int +shell_dlsym (int argc, char* argv[]) +{ + void* value; + if (lookup_dlsym (&value, argc, argv)) + { + printf ("%s = %p\n", argv[2], value); + return 0; + } + return -1; +} + +typedef int (*call_t)(int argc, char* argv[]); + +int +shell_dlcall (int argc, char* argv[]) +{ + void* value; + if (lookup_dlsym (&value, argc, argv)) + { + call_t call = value; + int r; + printf ("(*%p)(%d, ....)\n", value, argc - 3); + r = call (argc - 3, argv + 3); + printf ("return %d\n", r); + return 0; + } + return -1; +} diff --git a/cpukit/libdl/dlfcn-shell.h b/cpukit/libdl/dlfcn-shell.h new file mode 100644 index 0000000000..0406b6c784 --- /dev/null +++ b/cpukit/libdl/dlfcn-shell.h @@ -0,0 +1,17 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#if !defined(_DLFCN_SHELL_H_) +#define _DLFCN_SHELL_H_ + +int shell_dlopen (int argc, char* argv[]); +int shell_dlclose (int argc, char* argv[]); +int shell_dlsym (int argc, char* argv[]); +int shell_dlcall (int argc, char* argv[]); + +#endif diff --git a/cpukit/libdl/dlfcn.c b/cpukit/libdl/dlfcn.c new file mode 100644 index 0000000000..7c102022b2 --- /dev/null +++ b/cpukit/libdl/dlfcn.c @@ -0,0 +1,153 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtl + * + * @brief RTEMS POSIX Dynamic Module Loading Interface. + * + * This is the POSIX interface to run-time loading of code into RTEMS. + */ + +#include <stdint.h> +#include <dlfcn.h> +#include <rtems/rtl/rtl.h> + +static rtems_rtl_obj_t* +dl_get_obj_from_handle (void* handle) +{ + rtems_rtl_obj_t* obj; + + /* + * Handle the special cases provided in NetBSD and Sun documentation. + * http://download.oracle.com/docs/cd/E19253-01/816-5168/dlsym-3c/index.html + * We currently do not manage the loading dependences in the module mappings + * so we cannot handle the searching based on loading order where overriding + * can occur. + */ + + if ((handle == RTLD_DEFAULT) || (handle == RTLD_SELF)) + obj = rtems_rtl_baseimage (); + else + obj = rtems_rtl_check_handle (handle); + + return obj; +} + +void* +dlopen (const char* name, int mode) +{ + rtems_rtl_obj_t* obj = NULL; + + if (!rtems_rtl_lock ()) + return NULL; + + _rtld_debug.r_state = RT_ADD; + _rtld_debug_state (); + + if (name) + obj = rtems_rtl_load_object (name, mode); + else + obj = rtems_rtl_baseimage (); + + _rtld_debug.r_state = RT_CONSISTENT; + _rtld_debug_state(); + + rtems_rtl_unlock (); + + return obj; +} + +int +dlclose (void* handle) +{ + rtems_rtl_obj_t* obj; + int r; + + if (!rtems_rtl_lock ()) + return -1; + + obj = rtems_rtl_check_handle (handle); + if (!obj) + { + rtems_rtl_unlock (); + return -1; + } + + _rtld_debug.r_state = RT_DELETE; + _rtld_debug_state (); + + r = rtems_rtl_unload_object (obj) ? 0 : -1; + + _rtld_debug.r_state = RT_CONSISTENT; + _rtld_debug_state (); + + rtems_rtl_unlock (); + + return r; +} + +void* +dlsym (void* handle, const char *symbol) +{ + rtems_rtl_obj_t* obj; + rtems_rtl_obj_sym_t* sym; + void* symval = NULL; + + if (!rtems_rtl_lock ()) + return NULL; + + obj = dl_get_obj_from_handle (handle); + if (obj) + { + sym = rtems_rtl_symbol_obj_find (obj, symbol); + if (sym) + symval = sym->value; + } + + rtems_rtl_unlock (); + + return symval; +} + +const char* +dlerror (void) +{ + static char msg[64]; + rtems_rtl_get_error (msg, sizeof (msg)); + return msg; +} + +int +dlinfo (void* handle, int request, void* p) +{ + rtems_rtl_obj_t* obj; + int rc = -1; + + if (!rtems_rtl_lock () || !p) + return -1; + + obj = dl_get_obj_from_handle (handle); + if (obj) + { + switch (request) + { + case RTLD_DI_UNRESOLVED: + *((int*) p) = rtems_rtl_obj_unresolved (obj) ? 1 : 0; + rc = 0; + break; + default: + break; + } + } + + rtems_rtl_unlock (); + + return rc; +} diff --git a/cpukit/libdl/dlfcn.h b/cpukit/libdl/dlfcn.h new file mode 100644 index 0000000000..1ac3ba1330 --- /dev/null +++ b/cpukit/libdl/dlfcn.h @@ -0,0 +1,112 @@ +/* $NetBSD: dlfcn.h,v 1.21 2010/01/07 07:35:35 skrll Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Paul Kranenburg. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DLFCN_H_ +#define _DLFCN_H_ + +//#include <sys/featuretest.h> +#include <sys/cdefs.h> + +#if defined(_NETBSD_SOURCE) +typedef struct _dl_info { + const char *dli_fname; /* File defining the symbol */ + void *dli_fbase; /* Base address */ + const char *dli_sname; /* Symbol name */ + const void *dli_saddr; /* Symbol address */ +} Dl_info; +#endif /* defined(_NETBSD_SOURCE) */ + +/* + * User interface to the run-time linker. + */ +__BEGIN_DECLS +void *dlopen(const char *, int); +int dlclose(void *); +void *dlsym(void * __restrict, const char * __restrict); +#if defined(_NETBSD_SOURCE) +int dladdr(void * __restrict, Dl_info * __restrict); +int dlctl(void *, int, void *); +#endif +int dlinfo(void *, int, void *); +const char *dlerror(void); +__END_DECLS + +/* Values for dlopen `mode'. */ +#define RTLD_LAZY 1 +#define RTLD_NOW 2 +#define RTLD_GLOBAL 0x100 /* Allow global searches in object */ +#define RTLD_LOCAL 0x200 +#if defined(_NETBSD_SOURCE) +#define DL_LAZY RTLD_LAZY /* Compat */ +#endif + +/* + * Special handle arguments for dlsym(). + */ +#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */ +#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */ +#define RTLD_SELF ((void *) -3) /* Search the caller itself. */ + +/* + * dlctl() commands + */ +#if defined(_NETBSD_SOURCE) +#define DL_GETERRNO 1 +#define DL_GETSYMBOL 2 +#if 0 +#define DL_SETSRCHPATH x +#define DL_GETLIST x +#define DL_GETREFCNT x +#define DL_GETLOADADDR x +#endif /* 0 */ +#endif /* defined(_NETBSD_SOURCE) */ + +/* + * dlinfo() commands + * + * From Solaris: http://docs.sun.com/app/docs/doc/816-5168/dlinfo-3c?a=view + */ +#define RTLD_DI_UNRESOLVED 10 +#if defined(_NETBSD_SOURCE) +#define RTLD_DI_LINKMAP 3 +#if 0 +#define RTLD_DI_ARGSINFO 1 +#define RTLD_DI_CONFIGADDR 2 +#define RTLD_DI_LMID 4 +#define RTLD_DI_SERINFO 5 +#define RTLD_DI_SERINFOSIZE 6 +#define RTLD_DI_ORIGIN 7 +#define RTLD_DI_GETSIGNAL 8 +#define RTLD_DI_SETSIGNAL 9 +#endif +#endif /* _NETBSD_SOURCE */ + +#endif /* !defined(_DLFCN_H_) */ diff --git a/cpukit/libdl/fastlz.c b/cpukit/libdl/fastlz.c new file mode 100644 index 0000000000..3c9d6f6f86 --- /dev/null +++ b/cpukit/libdl/fastlz.c @@ -0,0 +1,551 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) + +/* + * Always check for bound when decompressing. + * Generally it is best to leave it defined. + */ +#define FASTLZ_SAFE + +/* + * Give hints to the compiler for branch prediction optimization. + */ +#if defined(__GNUC__) && (__GNUC__ > 2) +#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) +#else +#define FASTLZ_EXPECT_CONDITIONAL(c) (c) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) +#endif + +/* + * Use inlined functions for supported systems. + */ +#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) +#define FASTLZ_INLINE inline +#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) +#define FASTLZ_INLINE __inline +#else +#define FASTLZ_INLINE +#endif + +/* + * Prevent accessing more than 8-bit at once, except on x86 architectures. + */ +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_STRICT_ALIGN +#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(_M_IX86) /* Intel, MSVC */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__386) +#undef FASTLZ_STRICT_ALIGN +#elif defined(_X86_) /* MinGW */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__I86__) /* Digital Mars */ +#undef FASTLZ_STRICT_ALIGN +#endif +#endif + +/* + * FIXME: use preprocessor magic to set this on different platforms! + */ +typedef unsigned char flzuint8; +typedef unsigned short flzuint16; +typedef unsigned int flzuint32; + +/* prototypes */ +int fastlz_compress(const void* input, int length, void* output); +int fastlz_compress_level(int level, const void* input, int length, void* output); +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +#define MAX_COPY 32 +#define MAX_LEN 264 /* 256 + 8 */ +#define MAX_DISTANCE 8192 + +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_READU16(p) *((const flzuint16*)(p)) +#else +#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) +#endif + +#define HASH_LOG 13 +#define HASH_SIZE (1<< HASH_LOG) +#define HASH_MASK (HASH_SIZE-1) +#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 1 + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz1_compress +#define FASTLZ_DECOMPRESSOR fastlz1_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "fastlz.c" + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 2 + +#undef MAX_DISTANCE +#define MAX_DISTANCE 8191 +#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz2_compress +#define FASTLZ_DECOMPRESSOR fastlz2_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "fastlz.c" + +int fastlz_compress(const void* input, int length, void* output) +{ + /* for short block, choose fastlz1 */ + if(length < 65536) + return fastlz1_compress(input, length, output); + + /* else... */ + return fastlz2_compress(input, length, output); +} + +int fastlz_decompress(const void* input, int length, void* output, int maxout) +{ + /* magic identifier for compression level */ + int level = ((*(const flzuint8*)input) >> 5) + 1; + + if(level == 1) + return fastlz1_decompress(input, length, output, maxout); + if(level == 2) + return fastlz2_decompress(input, length, output, maxout); + + /* unknown level, trigger error */ + return 0; +} + +int fastlz_compress_level(int level, const void* input, int length, void* output) +{ + if(level == 1) + return fastlz1_compress(input, length, output); + if(level == 2) + return fastlz2_compress(input, length, output); + + return 0; +} + +#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ + +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_bound = ip + length - 2; + const flzuint8* ip_limit = ip + length - 12; + flzuint8* op = (flzuint8*) output; + + const flzuint8* htab[HASH_SIZE]; + const flzuint8** hslot; + flzuint32 hval; + + flzuint32 copy; + + /* sanity check */ + if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) + { + if(length) + { + /* create literal copy only */ + *op++ = length-1; + ip_bound++; + while(ip <= ip_bound) + *op++ = *ip++; + return length+1; + } + else + return 0; + } + + /* initializes hash table */ + for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) + *hslot = ip; + + /* we start with literal copy */ + copy = 2; + *op++ = MAX_COPY-1; + *op++ = *ip++; + *op++ = *ip++; + + /* main loop */ + while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + { + const flzuint8* ref; + flzuint32 distance; + + /* minimum match length */ + flzuint32 len = 3; + + /* comparison starting-point */ + const flzuint8* anchor = ip; + + /* check for a run */ +#if FASTLZ_LEVEL==2 + if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) + { + distance = 1; + ip += 3; + ref = anchor - 1 + 3; + goto match; + } +#endif + + /* find potential match */ + HASH_FUNCTION(hval,ip); + hslot = htab + hval; + ref = htab[hval]; + + /* calculate distance to the match */ + distance = anchor - ref; + + /* update hash table */ + *hslot = anchor; + + /* is this a match? check the first 3 bytes */ + if(distance==0 || +#if FASTLZ_LEVEL==1 + (distance >= MAX_DISTANCE) || +#else + (distance >= MAX_FARDISTANCE) || +#endif + *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) + goto literal; + +#if FASTLZ_LEVEL==2 + /* far, needs at least 5-byte match */ + if(distance >= MAX_DISTANCE) + { + if(*ip++ != *ref++ || *ip++!= *ref++) + goto literal; + len += 2; + } + + match: +#endif + + /* last matched byte */ + ip = anchor + len; + + /* distance is biased */ + distance--; + + if(!distance) + { + /* zero distance means a run */ + flzuint8 x = ip[-1]; + while(ip < ip_bound) + if(*ref++ != x) break; else ip++; + } + else + for(;;) + { + /* safe because the outer check against ip limit */ + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + while(ip < ip_bound) + if(*ref++ != *ip++) break; + break; + } + + /* if we have copied something, adjust the copy count */ + if(copy) + /* copy is biased, '0' means 1 byte copy */ + *(op-copy-1) = copy-1; + else + /* back, to overwrite the copy count */ + op--; + + /* reset literal counter */ + copy = 0; + + /* length is biased, '1' means a match of 3 bytes */ + ip -= 3; + len = ip - anchor; + + /* encode the match */ +#if FASTLZ_LEVEL==2 + if(distance < MAX_DISTANCE) + { + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = (distance & 255); + } + } + else + { + /* far away, but not yet in the another galaxy... */ + if(len < 7) + { + distance -= MAX_DISTANCE; + *op++ = (len << 5) + 31; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + else + { + distance -= MAX_DISTANCE; + *op++ = (7 << 5) + 31; + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + } +#else + + if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) + while(len > MAX_LEN-2) + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = MAX_LEN - 2 - 7 -2; + *op++ = (distance & 255); + len -= MAX_LEN-2; + } + + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = len - 7; + *op++ = (distance & 255); + } +#endif + + /* update the hash at match boundary */ + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + + /* assuming literal copy */ + *op++ = MAX_COPY-1; + + continue; + + literal: + *op++ = *anchor++; + ip = anchor; + copy++; + if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* left-over as literal copy */ + ip_bound++; + while(ip <= ip_bound) + { + *op++ = *ip++; + copy++; + if(copy == MAX_COPY) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* if we have copied something, adjust the copy length */ + if(copy) + *(op-copy-1) = copy-1; + else + op--; + +#if FASTLZ_LEVEL==2 + /* marker for fastlz2 */ + *(flzuint8*)output |= (1 << 5); +#endif + + return op - (flzuint8*)output; +} + +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_limit = ip + length; + flzuint8* op = (flzuint8*) output; + flzuint8* op_limit = op + maxout; + flzuint32 ctrl = (*ip++) & 31; + int loop = 1; + + do + { + const flzuint8* ref = op; + flzuint32 len = ctrl >> 5; + flzuint32 ofs = (ctrl & 31) << 8; + + if(ctrl >= 32) + { +#if FASTLZ_LEVEL==2 + flzuint8 code; +#endif + len--; + ref -= ofs; + if (len == 7-1) +#if FASTLZ_LEVEL==1 + len += *ip++; + ref -= *ip++; +#else + do + { + code = *ip++; + len += code; + } while (code==255); + code = *ip++; + ref -= code; + + /* match from 16-bit distance */ + if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) + if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) + { + ofs = (*ip++) << 8; + ofs += *ip++; + ref = op - ofs - MAX_DISTANCE; + } +#endif + +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) + return 0; + + if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) + return 0; +#endif + + if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + ctrl = *ip++; + else + loop = 0; + + if(ref == op) + { + /* optimize copy for a run */ + flzuint8 b = ref[-1]; + *op++ = b; + *op++ = b; + *op++ = b; + for(; len; --len) + *op++ = b; + } + else + { +#if !defined(FASTLZ_STRICT_ALIGN) + const flzuint16* p; + flzuint16* q; +#endif + /* copy from reference */ + ref--; + *op++ = *ref++; + *op++ = *ref++; + *op++ = *ref++; + +#if !defined(FASTLZ_STRICT_ALIGN) + /* copy a byte, so that now it's word aligned */ + if(len & 1) + { + *op++ = *ref++; + len--; + } + + /* copy 16-bit at once */ + q = (flzuint16*) op; + op += len; + p = (const flzuint16*) ref; + for(len>>=1; len > 4; len-=4) + { + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + } + for(; len; --len) + *q++ = *p++; +#else + for(; len; --len) + *op++ = *ref++; +#endif + } + } + else + { + ctrl++; +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) + return 0; + if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) + return 0; +#endif + + *op++ = *ip++; + for(--ctrl; ctrl; ctrl--) + *op++ = *ip++; + + loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); + if(loop) + ctrl = *ip++; + } + } + while(FASTLZ_EXPECT_CONDITIONAL(loop)); + + return op - (flzuint8*)output; +} + +#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ diff --git a/cpukit/libdl/fastlz.h b/cpukit/libdl/fastlz.h new file mode 100644 index 0000000000..f87bc7be31 --- /dev/null +++ b/cpukit/libdl/fastlz.h @@ -0,0 +1,100 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef FASTLZ_H +#define FASTLZ_H + +#define FASTLZ_VERSION 0x000100 + +#define FASTLZ_VERSION_MAJOR 0 +#define FASTLZ_VERSION_MINOR 0 +#define FASTLZ_VERSION_REVISION 0 + +#define FASTLZ_VERSION_STRING "0.1.0" + +#if defined (__cplusplus) +extern "C" { +#endif + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. +*/ + +int fastlz_compress(const void* input, int length, void* output); + +/** + Decompress a block of compressed data and returns the size of the + decompressed block. If error occurs, e.g. the compressed data is + corrupted or the output buffer is not large enough, then 0 (zero) + will be returned instead. + + The input buffer and the output buffer can not overlap. + + Decompression is memory safe and guaranteed not to write the output buffer + more than what is specified in maxout. + */ + +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. + + Compression level can be specified in parameter level. At the moment, + only level 1 and level 2 are supported. + Level 1 is the fastest compression and generally useful for short data. + Level 2 is slightly slower but it gives better compression ratio. + + Note that the compressed data, regardless of the level, can always be + decompressed using the function fastlz_decompress above. +*/ + +int fastlz_compress_level(int level, const void* input, int length, void* output); + +#if defined (__cplusplus) +} +#endif + +#endif /* FASTLZ_H */ diff --git a/cpukit/libdl/include/arch/arm/machine/elf_machdep.h b/cpukit/libdl/include/arch/arm/machine/elf_machdep.h new file mode 100644 index 0000000000..78c88b5af8 --- /dev/null +++ b/cpukit/libdl/include/arch/arm/machine/elf_machdep.h @@ -0,0 +1,131 @@ +/* $NetBSD: elf_machdep.h,v 1.8 2009/05/30 05:56:52 skrll Exp $ */ + +#if defined(__ARMEB__) +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB +#else +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2LSB +#endif + +#define ELF64_MACHDEP_ENDIANNESS XXX /* break compilation */ +#define ELF64_MACHDEP_ID_CASES \ + /* no 64-bit ELF machine types supported */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x00000001 +#define EF_ARM_HASENTRY 0x00000002 +#define EF_ARM_INTERWORK 0x00000004 /* GNU binutils 000413 */ +#define EF_ARM_SYMSARESORTED 0x00000004 /* ARM ELF A08 */ +#define EF_ARM_APCS_26 0x00000008 /* GNU binutils 000413 */ +#define EF_ARM_DYNSYMSUSESEGIDX 0x00000008 /* ARM ELF B01 */ +#define EF_ARM_APCS_FLOAT 0x00000010 /* GNU binutils 000413 */ +#define EF_ARM_MAPSYMSFIRST 0x00000010 /* ARM ELF B01 */ +#define EF_ARM_PIC 0x00000020 +#define EF_ARM_ALIGN8 0x00000040 /* 8-bit structure alignment. */ +#define EF_ARM_NEW_ABI 0x00000080 +#define EF_ARM_OLD_ABI 0x00000100 +#define EF_ARM_SOFT_FLOAT 0x00000200 +#define EF_ARM_EABIMASK 0xff000000 + +#define ELF32_MACHDEP_ID_CASES \ + case EM_ARM: \ + break; + +#define ELF32_MACHDEP_ID EM_ARM + +#define ARCH_ELFSIZE 32 /* MD native binary size */ + +/* Processor specific relocation types */ + +#define R_ARM_NONE 0 +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_CALL 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 + +/* TLS relocations */ +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ + +/* 20-31 are reserved for ARM Linux. */ +#define R_ARM_COPY 20 +#define R_ARM_GLOB_DAT 21 +#define R_ARM_JUMP_SLOT 22 +#define R_ARM_RELATIVE 23 +#define R_ARM_GOTOFF 24 +#define R_ARM_GOTPC 25 +#define R_ARM_GOT32 26 +#define R_ARM_PLT32 27 +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_THM_JUMP24 30 +#define R_ARM_BASE_ABS 31 + +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_ALU_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_V4BX 40 +#define R_ARM_PREL31 41 + +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 + +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 + +#define R_ARM_THM_JUMP19 51 + +/* 96-111 are reserved to G++. */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_JUMP11 102 +#define R_ARM_THM_JUMP8 103 + +/* More TLS relocations */ +#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic */ +#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic */ +#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS */ +#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of */ +#define R_ARM_TLS_LE32 108 +#define R_ARM_TLS_LDO12 109 +#define R_ARM_TLS_LE12 110 +#define R_ARM_TLS_IE12GP 111 + +/* 112-127 are reserved for private experiments. */ + +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +#define R_TYPE(name) __CONCAT(R_ARM_,name) + +/* Processor specific program header flags */ +#define PF_ARM_SB 0x10000000 +#define PF_ARM_PI 0x20000000 +#define PF_ARM_ENTRY 0x80000000 + +/* Processor specific section header flags */ +#define SHF_ENTRYSECT 0x10000000 +#define SHF_COMDEF 0x80000000 + +/* Processor specific symbol types */ +#define STT_ARM_TFUNC STT_LOPROC diff --git a/cpukit/libdl/include/arch/bfin/machine/elf_machdep.h b/cpukit/libdl/include/arch/bfin/machine/elf_machdep.h new file mode 100644 index 0000000000..cf0dc19221 --- /dev/null +++ b/cpukit/libdl/include/arch/bfin/machine/elf_machdep.h @@ -0,0 +1,28 @@ +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2LSB + +#define ELF32_MACHDEP_ID_CASES \ + case EM_BLACKFIN: \ + break; + +#define ELF32_MACHDEP_ID EM_BLACKFIN + +#define ARCH_ELFSIZE 32 + +#define R_BFIN_UNUSED0 0 + +#define R_BFIN_RIMM16 5 +#define R_BFIN_LUIMM16 6 +#define R_BFIN_HUIMM16 7 +#define R_BFIN_PCREL12_JUMP_S 8 +#define R_BFIN_PCREL24_JUMP_X 9 +#define R_BFIN_PCREL24 10 +#define R_BFIN_PCREL24_JU 13 +#define R_BFIN_PCREL24_CALL_X 14 + +#define R_BFIN_BYTE_DATA 16 +#define R_BFIN_BYTE2_DATA 17 +#define R_BFIN_BYTE4_DATA 18 + + + +#define R_TYPE(name) __CONCAT(R_BFIN_,name) diff --git a/cpukit/libdl/include/arch/h8300/machine/elf_machdep.h b/cpukit/libdl/include/arch/h8300/machine/elf_machdep.h new file mode 100644 index 0000000000..3d049157eb --- /dev/null +++ b/cpukit/libdl/include/arch/h8300/machine/elf_machdep.h @@ -0,0 +1,59 @@ + +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB + +#define ELF32_MACHDEP_ID_CASES \ + case EM_H8_300: \ + case EM_H8_300H: \ + case EM_H8S: \ + case EM_H8_500: \ + break; + +#define ELF32_MACHDEP_ID EM_H8_300 +#define ARCH_ELFSIZE 32 + +#define R_H8_NONE 0 +#define R_H8_DIR32 1 +#define R_H8_DIR32_28 2 +#define R_H8_DIR32_24 3 +#define R_H8_DIR32_16 4 +#define R_H8_DIR32U 6 +#define R_H8_DIR32U_28 7 +#define R_H8_DIR32U_24 8 +#define R_H8_DIR32U_20 9 +#define R_H8_DIR32U_16 10 +#define R_H8_DIR24 11 +#define R_H8_DIR24_20 12 +#define R_H8_DIR24_16 13 +#define R_H8_DIR24U 14 +#define R_H8_DIR24U_20 15 +#define R_H8_DIR24U_16 16 +#define R_H8_DIR16 17 +#define R_H8_DIR16U 18 +#define R_H8_DIR16S_32 19 +#define R_H8_DIR16S_28 20 +#define R_H8_DIR16S_24 21 +#define R_H8_DIR16S_20 22 +#define R_H8_DIR16S 23 +#define R_H8_DIR8 24 +#define R_H8_DIR8U 25 +#define R_H8_DIR8Z_32 26 +#define R_H8_DIR8Z_28 27 +#define R_H8_DIR8Z_24 28 +#define R_H8_DIR8Z_20 29 +#define R_H8_DIR8Z_16 30 +#define R_H8_PCREL16 31 +#define R_H8_PCREL8 32 +#define R_H8_BPOS 33 +#define R_H8_PCREL32 34 +#define R_H8_GOT32O 35 +#define R_H8_GOT16O 36 +#define R_H8_DIR16A8 59 +#define R_H8_DIR16R8 60 +#define R_H8_DIR24A8 61 +#define R_H8_DIR24R8 62 +#define R_H8_DIR32A16 63 +#define R_H8_ABS32 65 +#define R_H8_ABS32A16 127 + + +#define R_TYPE(name) __CONCAT(R_H8_,name) diff --git a/cpukit/libdl/include/arch/i386/machine/elf_machdep.h b/cpukit/libdl/include/arch/i386/machine/elf_machdep.h new file mode 100644 index 0000000000..442c561a9c --- /dev/null +++ b/cpukit/libdl/include/arch/i386/machine/elf_machdep.h @@ -0,0 +1,63 @@ +/* $NetBSD: elf_machdep.h,v 1.10 2009/05/30 05:56:52 skrll Exp $ */ + +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2LSB +#define ELF32_MACHDEP_ID_CASES \ + case EM_386: \ + case EM_486: \ + break; + +#define ELF64_MACHDEP_ENDIANNESS XXX /* break compilation */ +#define ELF64_MACHDEP_ID_CASES \ + /* no 64-bit ELF machine types supported */ + +#define ELF32_MACHDEP_ID EM_386 + +#define ARCH_ELFSIZE 32 /* MD native binary size */ + +/* i386 relocations */ +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 + +/* TLS relocations */ +#define R_386_TLS_TPOFF 14 +#define R_386_TLS_IE 15 +#define R_386_TLS_GOTIE 16 +#define R_386_TLS_LE 17 +#define R_386_TLS_GD 18 +#define R_386_TLS_LDM 19 + +/* The following relocations are GNU extensions. */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 + +/* More TLS relocations */ +#define R_386_TLS_GD_32 24 +#define R_386_TLS_GD_PUSH 25 +#define R_386_TLS_GD_CALL 26 +#define R_386_TLS_GD_POP 27 +#define R_386_TLS_LDM_32 28 +#define R_386_TLS_LDM_PUSH 29 +#define R_386_TLS_LDM_CALL 30 +#define R_386_TLS_LDM_POP 31 +#define R_386_TLS_LDO_32 32 +#define R_386_TLS_IE_32 33 +#define R_386_TLS_LE_32 34 +#define R_386_TLS_DTPMOD32 35 +#define R_386_TLS_DTPOFF32 36 +#define R_386_TLS_TPOFF32 37 +#define R_386_TLS_GOTDESC 39 +#define R_386_TLS_DESC_CALL 40 +#define R_386_TLS_DESC 41 + +#define R_TYPE(name) __CONCAT(R_386_,name) diff --git a/cpukit/libdl/include/arch/lm32/machine/elf_machdep.h b/cpukit/libdl/include/arch/lm32/machine/elf_machdep.h new file mode 100644 index 0000000000..29c75b89db --- /dev/null +++ b/cpukit/libdl/include/arch/lm32/machine/elf_machdep.h @@ -0,0 +1,34 @@ +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB + +#define ELF32_MACHDEP_ID_CASES \ + case EM_LATTICEMICO32: \ + break; + +#define ELF32_MACHDEP_ID EM_LATTICEMICO32 + +#define EF_MACH32_MACH 0x00000001 + +//#define EF_BLACKFIN + +#define ARCH_ELFSIZE 32 + +#define R_LM32_NONE 0 +#define R_LM32_8 1 +#define R_LM32_16 2 +#define R_LM32_32 3 +#define R_LM32_HI16 4 +#define R_LM32_LO16 5 +#define R_LM32_GPREL16 6 +#define R_LM32_CALL 7 +#define R_LM32_BRANCH 8 +#define R_LM32_GNU_VTINHERIT 9 +#define R_LM32_GNU_VTENTRY 10 +#define R_LM32_16_GOT 11 +#define R_LM32_GOTOFF_HI16 12 +#define R_LM32_GOTOFF_LO16 13 +#define R_LM32_COPY 14 +#define R_LM32_GLOT_DAT 15 +#define R_LM32_JMP_SLOT 16 +#define R_LM32_RELATIVE 17 + +#define R_TYPE(name) __CONCAT(R_LM32_,name) diff --git a/cpukit/libdl/include/arch/m32r/machine/elf_machdep.h b/cpukit/libdl/include/arch/m32r/machine/elf_machdep.h new file mode 100644 index 0000000000..3f531cf901 --- /dev/null +++ b/cpukit/libdl/include/arch/m32r/machine/elf_machdep.h @@ -0,0 +1,39 @@ +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB + +#define ELF32_MACHDEP_ID_CASES \ + case EM_M32R: \ + break; + +#define ELF32_MACHDEP_ID EM_M32R + +#define ARCH_ELFSIZE 32 + +#define R_M32R_NONE 0 +/*-----------OLD TYPE-------------*/ +#define R_M32R_16 1 +#define R_M32R_32 2 +#define R_M32R_24 3 +#define R_M32R_10_PCREL 4 +#define R_M32R_18_PCREL 5 +#define R_M32R_26_PCREL 6 +#define R_M32R_HI16_ULO 7 +#define R_M32R_HI16_SLO 8 +#define R_M32R_LO16 9 +#define R_M32R_SDA16 10 +#define R_M32R_GNU_VTINHERIT 11 +#define R_M32R_GNU_VTENTRY 12 +/*--------------------------------*/ + +#define R_M32R_16_RELA 33 +#define R_M32R_32_RELA 34 +#define R_M32R_24_RELA 35 +#define R_M32R_18_PCREL_RELA 37 +#define R_M32R_26_PCREL_RELA 38 +#define R_M32R_HI16_ULO_RELA 39 +#define R_M32R_HI16_SLO_RELA 40 +#define R_M32R_LO16_RELA 41 +#define R_M32R_SDA16_RELA 42 +#define R_M32R_RELA_GNU_VTINHERIT 43 +#define R_M32R_RELA_GNU_VTENTRY 44 + +#define R_TYPE(name) __CONCAT(R_M32R_,name) diff --git a/cpukit/libdl/include/arch/m68k/machine/elf_machdep.h b/cpukit/libdl/include/arch/m68k/machine/elf_machdep.h new file mode 100644 index 0000000000..9a987c69b5 --- /dev/null +++ b/cpukit/libdl/include/arch/m68k/machine/elf_machdep.h @@ -0,0 +1,47 @@ +/* $NetBSD: elf_machdep.h,v 1.7 2002/01/28 21:34:48 thorpej Exp $ */ + +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB +#define ELF32_MACHDEP_ID_CASES \ + case EM_68K: \ + break; + +#define ELF64_MACHDEP_ENDIANNESS XXX /* break compilation */ +#define ELF64_MACHDEP_ID_CASES \ + /* no 64-bit ELF machine types supported */ + +#define ELF32_MACHDEP_ID EM_68K + +/* + * Machine-dependent ELF flags. These are defined by the GNU tools. + */ +#define EF_CPU32 0x00810000 +#define EF_M68000 0x01000000 + +#define ARCH_ELFSIZE 32 /* MD native binary size */ + +/* m68k relocation types */ +#define R_68K_NONE 0 +#define R_68K_32 1 +#define R_68K_16 2 +#define R_68K_8 3 +#define R_68K_PC32 4 +#define R_68K_PC16 5 +#define R_68K_PC8 6 +#define R_68K_GOT32 7 +#define R_68K_GOT16 8 +#define R_68K_GOT8 9 +#define R_68K_GOT32O 10 +#define R_68K_GOT16O 11 +#define R_68K_GOT8O 12 +#define R_68K_PLT32 13 +#define R_68K_PLT16 14 +#define R_68K_PLT8 15 +#define R_68K_PLT32O 16 +#define R_68K_PLT16O 17 +#define R_68K_PLT8O 18 +#define R_68K_COPY 19 +#define R_68K_GLOB_DAT 20 +#define R_68K_JMP_SLOT 21 +#define R_68K_RELATIVE 22 + +#define R_TYPE(name) __CONCAT(R_68K_,name) diff --git a/cpukit/libdl/include/arch/mips/machine/elf_machdep.h b/cpukit/libdl/include/arch/mips/machine/elf_machdep.h new file mode 100644 index 0000000000..d27d431835 --- /dev/null +++ b/cpukit/libdl/include/arch/mips/machine/elf_machdep.h @@ -0,0 +1,196 @@ +/* $NetBSD: elf_machdep.h,v 1.15 2011/03/15 07:39:22 matt Exp $ */ + +#ifndef _MIPS_ELF_MACHDEP_H_ +#define _MIPS_ELF_MACHDEP_H_ + +#ifdef _LP64 +#define ARCH_ELFSIZE 64 /* MD native binary size */ +#else +#define ARCH_ELFSIZE 32 /* MD native binary size */ +#endif + +#if ELFSIZE == 32 +#define ELF32_MACHDEP_ID_CASES \ + case EM_MIPS: \ + break; + +#define ELF32_MACHDEP_ID EM_MIPS +#elif ELFSIZE == 64 +#define ELF64_MACHDEP_ID_CASES \ + case EM_MIPS: \ + break; + +#define ELF64_MACHDEP_ID EM_MIPS +#endif + +/* mips relocs. */ + +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_REL R_MIPS_REL32 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 /* high 16 bits of symbol value */ +#define R_MIPS_LO16 6 /* low 16 bits of symbol value */ +#define R_MIPS_GPREL16 7 /* GP-relative reference */ +#define R_MIPS_LITERAL 8 /* Reference to literal section */ +#define R_MIPS_GOT16 9 /* Reference to global offset table */ +#define R_MIPS_GOT R_MIPS_GOT16 +#define R_MIPS_PC16 10 /* 16 bit PC relative reference */ +#define R_MIPS_CALL16 11 /* 16 bit call thru glbl offset tbl */ +#define R_MIPS_CALL R_MIPS_CALL16 +#define R_MIPS_GPREL32 12 + +/* 13, 14, 15 are not defined at this point. */ +#define R_MIPS_UNUSED1 13 +#define R_MIPS_UNUSED2 14 +#define R_MIPS_UNUSED3 15 + +/* + * The remaining relocs are apparently part of the 64-bit Irix ELF ABI. + */ +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 + +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +/* TLS relocations */ + +#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ +#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ +#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ +#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ +#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ +#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ +#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ +#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ +#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ +#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ +#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ +#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ +#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ + +#define R_MIPS_max 51 + +#define R_TYPE(name) __CONCAT(R_MIPS_,name) + +#define R_MIPS16_min 100 +#define R_MIPS16_26 100 +#define R_MIPS16_GPREL 101 +#define R_MIPS16_GOT16 102 +#define R_MIPS16_CALL16 103 +#define R_MIPS16_HI16 104 +#define R_MIPS16_LO16 105 +#define R_MIPS16_max 106 + + +/* mips dynamic tags */ + +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* number of local got ents */ +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 /* number of .dynsym entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 /* first dynamic sym in got */ +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 /* address of loader map */ + +/* + * ELF Flags + */ +#define EF_MIPS_PIC 0x00000002 /* Contains PIC code */ +#define EF_MIPS_CPIC 0x00000004 /* STD PIC calling sequence */ +#define EF_MIPS_ABI2 0x00000020 /* N32 */ + +#define EF_MIPS_ARCH_ASE 0x0f000000 /* Architectural extensions */ +#define EF_MIPS_ARCH_MDMX 0x08000000 /* MDMX multimedia extension */ +#define EF_MIPS_ARCH_M16 0x04000000 /* MIPS-16 ISA extensions */ + +#define EF_MIPS_ARCH 0xf0000000 /* Architecture field */ +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code */ +#define EF_MIPS_ARCH_32 0x50000000 /* -mips32 code */ +#define EF_MIPS_ARCH_64 0x60000000 /* -mips64 code */ +#define EF_MIPS_ARCH_32R2 0x70000000 /* -mips32r2 code */ +#define EF_MIPS_ARCH_64R2 0x80000000 /* -mips64r2 code */ + +#define EF_MIPS_ABI 0x0000f000 +#define EF_MIPS_ABI_O32 0x00001000 +#define EF_MIPS_ABI_O64 0x00002000 +#define EF_MIPS_ABI_EABI32 0x00003000 +#define EF_MIPS_ABI_EABI64 0x00004000 + +#if defined(__MIPSEB__) +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB +#define ELF64_MACHDEP_ENDIANNESS ELFDATA2MSB +#elif defined(__MIPSEL__) +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2LSB +#define ELF64_MACHDEP_ENDIANNESS ELFDATA2LSB +#elif !defined(HAVE_NBTOOL_CONFIG_H) +#error neither __MIPSEL__ nor __MIPSEB__ are defined. +#endif + +#ifdef _KERNEL +#ifdef _KERNEL_OPT +#include "opt_compat_netbsd.h" +#endif +#ifdef COMPAT_16 +/* + * Up to 1.6, the ELF dynamic loader (ld.elf_so) was not relocatable. + * Tell the kernel ELF exec code not to try relocating the interpreter + * for dynamically-linked ELF binaries. + */ +#define ELF_INTERP_NON_RELOCATABLE +#endif /* COMPAT_16 */ + +/* + * We need to be able to include the ELF header so we can pick out the + * ABI being used. + */ +#ifdef ELFSIZE +#define ELF_MD_PROBE_FUNC ELFNAME2(mips_netbsd,probe) +#define ELF_MD_COREDUMP_SETUP ELFNAME2(coredump,setup) +#endif + +struct exec_package; + +int mips_netbsd_elf32_probe(struct lwp *, struct exec_package *, void *, char *, + vaddr_t *); +void coredump_elf32_setup(struct lwp *, void *); + +int mips_netbsd_elf64_probe(struct lwp *, struct exec_package *, void *, char *, + vaddr_t *); +void coredump_elf64_setup(struct lwp *, void *); +#endif /* _KERNEL */ + +#endif /* _MIPS_ELF_MACHDEP_H_ */ diff --git a/cpukit/libdl/include/arch/moxie/machine/elf_machdep.h b/cpukit/libdl/include/arch/moxie/machine/elf_machdep.h new file mode 100644 index 0000000000..3f0df23cdc --- /dev/null +++ b/cpukit/libdl/include/arch/moxie/machine/elf_machdep.h @@ -0,0 +1,15 @@ +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB + +#define ELF32_MACHDEP_ID_CASES \ + case EM_MOXIE: \ + break; + +#define ELF32_MACHDEP_ID EM_MOXIE + +#define ARCH_ELFSIZE 32 + +#define R_MOXIE_NONE 0 +#define R_MOXIE_32 1 +#define R_MOXIE_PCREL10 2 + +#define R_TYPE(name) __CONCAT(R_MOXIE_,name) diff --git a/cpukit/libdl/include/arch/nios2/machine/elf_machdep.h b/cpukit/libdl/include/arch/nios2/machine/elf_machdep.h new file mode 100644 index 0000000000..3f3c108bf5 --- /dev/null +++ b/cpukit/libdl/include/arch/nios2/machine/elf_machdep.h @@ -0,0 +1,46 @@ +/* $NetBSD: elf_machdep.h,v 1.7 2002/01/28 21:34:48 thorpej Exp $ */ + +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB +#define ELF32_MACHDEP_ID_CASES \ + case EM_ALTERA_NIOS2: \ + break; + +#define ELF64_MACHDEP_ENDIANNESS XXX /* break compilation */ +#define ELF64_MACHDEP_ID_CASES \ + /* no 64-bit ELF machine types supported */ + +#define ELF32_MACHDEP_ID EM_ALTERA_NIOS2 + +/* + * Machine-dependent ELF flags. These are defined by the GNU tools. + */ +#define EF_NIOS2 0x00810000 + +#define ARCH_ELFSIZE 32 /* MD native binary size */ + +/* NIOS2 relocation types */ +#define R_NIOS2_NONE 0 +#define R_NIOS2_32 1 +#define R_NIOS2_16 2 +#define R_NIOS2_8 3 +#define R_NIOS2_PC32 4 +#define R_NIOS2_PC16 5 +#define R_NIOS2_PC8 6 +#define R_NIOS2_GOT32 7 +#define R_NIOS2_GOT16 8 +#define R_NIOS2_GOT8 9 +#define R_NIOS2_GOT32O 10 +#define R_NIOS2_GOT16O 11 +#define R_NIOS2_GOT8O 12 +#define R_NIOS2_PLT32 13 +#define R_NIOS2_PLT16 14 +#define R_NIOS2_PLT8 15 +#define R_NIOS2_PLT32O 16 +#define R_NIOS2_PLT16O 17 +#define R_NIOS2_PLT8O 18 +#define R_NIOS2_COPY 19 +#define R_NIOS2_GLOB_DAT 20 +#define R_NIOS2_JMP_SLOT 21 +#define R_NIOS2_RELATIVE 22 + +#define R_TYPE(name) __CONCAT(R_NIOS2_,name) diff --git a/cpukit/libdl/include/arch/powerpc/machine/elf_machdep.h b/cpukit/libdl/include/arch/powerpc/machine/elf_machdep.h new file mode 100644 index 0000000000..f0fdb3f33b --- /dev/null +++ b/cpukit/libdl/include/arch/powerpc/machine/elf_machdep.h @@ -0,0 +1,105 @@ +/* $NetBSD: elf_machdep.h,v 1.9 2011/01/15 10:00:07 matt Exp $ */ + +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB +#define ELF32_MACHDEP_ID_CASES \ + case EM_PPC: \ + break; + +#define ELF64_MACHDEP_ENDIANNESS ELFDATA2MSB +#define ELF64_MACHDEP_ID_CASES \ + case EM_PPC64: \ + break; + +#define ELF32_MACHDEP_ID EM_PPC +#define ELF64_MACHDEP_ID EM_PPC64 + +#ifdef _LP64 +#define ARCH_ELFSIZE 64 /* MD native binary size */ +#else +#define ARCH_ELFSIZE 32 /* MD native binary size */ +#endif + +/* Specify the value of _GLOBAL_OFFSET_TABLE_ */ +#define DT_PPC_GOT DT_LOPROC + +#define R_PPC_NONE 0 +#define R_PPC_32 1 +#define R_PPC_24 2 +#define R_PPC_16 3 +#define R_PPC_16_LO 4 +#define R_PPC_16_HI 5 /* R_PPC_ADDIS */ +#define R_PPC_16_HA 6 +#define R_PPC_14 7 +#define R_PPC_14_TAKEN 8 +#define R_PPC_14_NTAKEN 9 +#define R_PPC_REL24 10 /* R_PPC_BRANCH */ +#define R_PPC_REL14 11 +#define R_PPC_REL14_TAKEN 12 +#define R_PPC_REL14_NTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLT24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_U32 24 +#define R_PPC_U16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +#define R_PPC_ADDR30 37 + +/* TLS relocations */ +#define R_PPC_TLS 67 + +#define R_PPC_DTPMOD32 68 +#define R_PPC_TPREL16 69 +#define R_PPC_TPREL16_LO 70 +#define R_PPC_TPREL16_HI 71 +#define R_PPC_TPREL16_HA 72 +#define R_PPC_TPREL32 73 +#define R_PPC_DTPREL16 74 +#define R_PPC_DTPREL16_LO 75 +#define R_PPC_DTPREL16_HI 76 +#define R_PPC_DTPREL16_HA 77 +#define R_PPC_DTPREL32 78 + +#define R_PPC_GOT_TLSGD16 79 +#define R_PPC_GOT_TLSGD16_LO 80 +#define R_PPC_GOT_TLSGD16_HI 81 +#define R_PPC_GOT_TLSGD16_HA 82 +#define R_PPC_GOT_TLSLD16 83 +#define R_PPC_GOT_TLSLD16_LO 84 +#define R_PPC_GOT_TLSLD16_HI 85 +#define R_PPC_GOT_TLSLD16_HA 86 + +#define R_PPC_GOT_TPREL16 87 +#define R_PPC_GOT_TPREL16_LO 88 +#define R_PPC_GOT_TPREL16_HI 89 +#define R_PPC_GOT_TPREL16_HA 90 +#define R_PPC_GOT_DTPREL16 91 +#define R_PPC_GOT_DTPREL16_LO 92 +#define R_PPC_GOT_DTPREL16_HI 93 +#define R_PPC_GOT_DTPREL16_HA 94 +#define R_PPC_TLSGD 95 +#define R_PPC_TLSLD 96 + +/* Used for the secure-plt PIC code sequences */ +#define R_PPC_REL16 249 +#define R_PPC_REL16_LO 250 +#define R_PPC_REL16_HI 251 +#define R_PPC_REL16_HA 252 + +#define R_TYPE(name) __CONCAT(R_PPC_,name) diff --git a/cpukit/libdl/include/arch/sparc/machine/elf_machdep.h b/cpukit/libdl/include/arch/sparc/machine/elf_machdep.h new file mode 100644 index 0000000000..e8f2b630c2 --- /dev/null +++ b/cpukit/libdl/include/arch/sparc/machine/elf_machdep.h @@ -0,0 +1,92 @@ +/* $NetBSD: elf_machdep.h,v 1.7 2009/05/30 05:56:53 skrll Exp $ */ + +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB +#define ELF32_MACHDEP_ID_CASES \ + case EM_SPARC: \ + case EM_SPARC32PLUS: \ + break; + +#define ELF64_MACHDEP_ENDIANNESS ELFDATA2MSB +#define ELF64_MACHDEP_ID_CASES \ + case EM_SPARC32PLUS: \ + case EM_SPARCV9: \ + /* no 64-bit ELF machine types supported */ + +#define ELF32_MACHDEP_ID EM_SPARC /* XXX right? */ + +#define ARCH_ELFSIZE 32 /* MD native binary size */ + +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_PC_HH22 37 +#define R_SPARC_PC_HM10 38 +#define R_SPARC_PC_LM22 39 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_GLOB_JMP 42 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 + +/* TLS relocations */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 + +#define R_TYPE(name) __CONCAT(R_SPARC_,name) diff --git a/cpukit/libdl/include/arch/v850/machine/elf_machdep.h b/cpukit/libdl/include/arch/v850/machine/elf_machdep.h new file mode 100644 index 0000000000..b76d1491d6 --- /dev/null +++ b/cpukit/libdl/include/arch/v850/machine/elf_machdep.h @@ -0,0 +1,74 @@ +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2LSB + +#define ELF32_MACHDEP_ID_CASES \ + case EM_V850: \ + break; + +#define ELF32_MACHDEP_ID EM_V850 + + + +#define EF_V850_ARCH 0xf0000000 +#define E_V850_ARCH 0x00000000 +#define E_V850E_ARCH 0x10000000 +#define E_V850E1_ARCH 0x20000000 +#define E_V850E2_ARCH 0x30000000 +#define E_V850E2V3_ARCH 0x40000000 + +#define ARCH_ELFSIZE 32 + + +#define R_V850_NONE 0 +#define R_V850_9_PCREL 1 +#define R_V850_22_PCREL 2 +#define R_V850_HI16_S 3 +#define R_V850_HI16 4 +#define R_V850_LO16 5 +#define R_V850_ABS32 6 +#define R_V850_16 7 +#define R_V850_8 8 +#define R_V850_SDA_16_16_OFFSET 9 +#define R_V850_SDA_15_16_OFFSET 10 +#define R_V850_ZDA_16_16_OFFSET 11 +#define R_V850_ZDA_15_16_OFFSET 12 +#define R_V850_TDA_6_8_OFFSET 13 +#define R_V850_TDA_7_8_OFFSET 14 +#define R_V850_TDA_7_7_OFFSET 15 +#define R_V850_TDA_16_16_OFFSET 16 +#define R_V850_TDA_4_5_OFFSET 17 +#define R_V850_TDA_4_4_OFFSET 18 +#define R_V850_SDA_16_16_SPLIT_OFFSET 19 +#define R_V850_ZDA_16_16_SPLIT_OFFSET 20 +#define R_V850_CALLT_6_7_OFFSET 21 +#define R_V850_CALLT_16_16_OFFSET 22 +#define R_V850_GNU_VTINHERIT 23 +#define R_V850_GNU_VTENTRY 24 +#define R_V850_LONGCALL 25 +#define R_V850_LONGJUMP 26 +#define R_V850_ALIGN 27 +#define R_V850_REL32 28 +#define R_V850_LO16_SPLIT_OFFSET 29 +#define R_V850_16_PCREL 30 +#define R_V850_17_PCREL 31 +#define R_V850_23 32 +#define R_V850_32_PCREL 33 +#define R_V850_32_ABS 34 +#define R_V850_16_SPLIT_OFFSET 35 +#define R_V850_16_S1 36 +#define R_V850_LO16_S1 37 +#define R_V850_CALLT_15_16_OFFSET 38 +#define R_V850_32_GOTPCREL 39 +#define R_V850_16_GOT 40 +#define R_V850_32_GOT 41 +#define R_V850_22_PLT 42 +#define R_V850_32_PLT 43 +#define R_V850_COPY 44 +#define R_V850_GLOB_DAT 45 +#define R_V850_JMP_SLOT 46 +#define R_V850_RELATIVE 47 +#define R_V850_16_GOTOFF 48 +#define R_V850_32_GOTOFF 49 +#define R_V850_CODE 50 +#define R_V850_DATA 51 + +#define R_TYPE(name) __CONCAT(R_V850_,name) diff --git a/cpukit/libdl/include/link.h b/cpukit/libdl/include/link.h new file mode 100644 index 0000000000..c93efd9e78 --- /dev/null +++ b/cpukit/libdl/include/link.h @@ -0,0 +1,45 @@ +/* $NetBSD: link.h,v 1.13 2008/04/28 20:22:54 martin Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINK_H_ +#define _LINK_H_ + +/* + * Pull in the correct definitions for our toolchain target. + */ +#ifdef __ELF__ +#include <link_elf.h> +#else +#include <link_aout.h> +#endif + +#endif /* _LINK_H_ */ diff --git a/cpukit/libdl/include/link_elf.h b/cpukit/libdl/include/link_elf.h new file mode 100644 index 0000000000..d2691b68b0 --- /dev/null +++ b/cpukit/libdl/include/link_elf.h @@ -0,0 +1,79 @@ +/* $NetBSD: link_elf.h,v 1.8 2009/11/04 19:28:03 pooka Exp $ */ + +/* + * This only exists for GDB. + */ + +#ifndef _LINK_ELF_H_ +#define _LINK_ELF_H_ + +#include <sys/types.h> + +#include <machine/elf_machdep.h> +#include <stdint.h> +#include <rtems/rtl/rtl-obj-fwd.h> + +enum sections +{ + rap_text = 0, + rap_const = 1, + rap_ctor = 2, + rap_dtor = 3, + rap_data = 4, + rap_bss = 5, + rap_secs = 6 +}; + +/** + * Object details. + */ +typedef struct +{ + const char* name; /**< Section name. */ + uint32_t offset; /**< The offset in the elf file. */ + uint32_t size; /**< The size of the section. */ + uint32_t rap_id; /**< Which obj does this section belongs to. */ +}section_detail; + +/** + * link map structure will be used for GDB support. + */ +struct link_map { + const char* name; /**< Name of the obj. */ + uint32_t sec_num; /**< The count of section. */ + section_detail* sec_detail; /**< The section details. */ + uint32_t* sec_addr[rap_secs]; /**< The RAP section addr. */ + uint32_t rpathlen; /**< The length of the path. */ + char* rpath; /**< The path of object files. */ + struct link_map* l_next; /**< Linked list of mapped libs. */ + struct link_map* l_prev; +}; + +/** + * r_debug is used to manage the debug related structures. + */ +struct r_debug { + int r_version; /* not used */ + struct link_map *r_map; /* list of loaded images */ + enum { + RT_CONSISTENT, /* things are stable */ + RT_ADD, /* adding a shared library */ + RT_DELETE /* removing a shared library */ + } r_state; +}; + +/* + * stub function. It is empty. + */ +void _rtld_debug_state (void); + +/* + * add link map to the list. + */ +int _rtld_linkmap_add (rtems_rtl_obj_t* obj); + +/* + * Remove link map from the list. + */ +void _rtld_linkmap_delete (rtems_rtl_obj_t* obj); +#endif /* _LINK_ELF_H_ */ diff --git a/cpukit/libdl/include/sys/cdefs_elf.h b/cpukit/libdl/include/sys/cdefs_elf.h new file mode 100644 index 0000000000..91903d6017 --- /dev/null +++ b/cpukit/libdl/include/sys/cdefs_elf.h @@ -0,0 +1,152 @@ +/* $NetBSD: cdefs_elf.h,v 1.24 2005/07/16 17:53:36 christos Exp $ */ + +/* + * Copyright (c) 1995, 1996 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#ifndef _SYS_CDEFS_ELF_H_ +#define _SYS_CDEFS_ELF_H_ + +#ifdef __LEADING_UNDERSCORE +#define _C_LABEL(x) __CONCAT(_,x) +#define _C_LABEL_STRING(x) "_"x +#else +#define _C_LABEL(x) x +#define _C_LABEL_STRING(x) x +#endif + +#if __STDC__ +#define ___RENAME(x) __asm__(___STRING(_C_LABEL(x))) +#else +#ifdef __LEADING_UNDERSCORE +#define ___RENAME(x) ____RENAME(_/**/x) +#define ____RENAME(x) __asm__(___STRING(x)) +#else +#define ___RENAME(x) __asm__(___STRING(x)) +#endif +#endif + +#define __indr_reference(sym,alias) /* nada, since we do weak refs */ + +#if __STDC__ +#define __strong_alias(alias,sym) \ + __asm__(".global " _C_LABEL_STRING(#alias) "\n" \ + _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym)); + +#define __weak_alias(alias,sym) \ + __asm__(".weak " _C_LABEL_STRING(#alias) "\n" \ + _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym)); +#define __weak_extern(sym) \ + __asm__(".weak " _C_LABEL_STRING(#sym)); +#define __warn_references(sym,msg) \ + __asm__(".section .gnu.warning." #sym "\n\t.ascii \"" msg "\"\n\t.text"); + +#else /* !__STDC__ */ + +#ifdef __LEADING_UNDERSCORE +#define __weak_alias(alias,sym) ___weak_alias(_/**/alias,_/**/sym) +#define ___weak_alias(alias,sym) \ + __asm__(".weak alias\nalias = sym"); +#else +#define __weak_alias(alias,sym) \ + __asm__(".weak alias\nalias = sym"); +#endif +#ifdef __LEADING_UNDERSCORE +#define __weak_extern(sym) ___weak_extern(_/**/sym) +#define ___weak_extern(sym) \ + __asm__(".weak sym"); +#else +#define __weak_extern(sym) \ + __asm__(".weak sym"); +#endif +#define __warn_references(sym,msg) \ + __asm__(".section .gnu.warning.sym\n\t.ascii msg ; .text"); + +#endif /* !__STDC__ */ + +#if __STDC__ +#define __SECTIONSTRING(_sec, _str) \ + __asm__(".section " #_sec "\n\t.asciz \"" _str "\"\n\t.previous") +#else +#define __SECTIONSTRING(_sec, _str) \ + __asm__(".section _sec\n\t.asciz _str\n\t.previous") +#endif + +#define __IDSTRING(_n,_s) __SECTIONSTRING(.ident,_s) + +#define __RCSID(_s) __IDSTRING(rcsid,_s) +#define __SCCSID(_s) +#define __SCCSID2(_s) +#if 0 /* XXX userland __COPYRIGHTs have \ns in them */ +#define __COPYRIGHT(_s) __SECTIONSTRING(.copyright,_s) +#else +#define __COPYRIGHT(_s) \ + static const char copyright[] \ + __attribute__((__unused__,__section__(".copyright"))) = _s +#endif + +#define __KERNEL_RCSID(_n, _s) __RCSID(_s) +#define __KERNEL_SCCSID(_n, _s) +#if 0 /* XXX see above */ +#define __KERNEL_COPYRIGHT(_n, _s) __COPYRIGHT(_s) +#else +#define __KERNEL_COPYRIGHT(_n, _s) __SECTIONSTRING(.copyright, _s) +#endif + +#ifndef __lint__ +#define __link_set_make_entry(set, sym) \ + static void const * const __link_set_##set##_sym_##sym \ + __section("link_set_" #set) __used = &sym +#define __link_set_make_entry2(set, sym, n) \ + static void const * const __link_set_##set##_sym_##sym##_##n \ + __section("link_set_" #set) __used = &sym[n] +#else +#define __link_set_make_entry(set, sym) \ + extern void const * const __link_set_##set##_sym_##sym +#define __link_set_make_entry2(set, sym, n) \ + extern void const * const __link_set_##set##_sym_##sym##_##n +#endif /* __lint__ */ + +#define __link_set_add_text(set, sym) __link_set_make_entry(set, sym) +#define __link_set_add_rodata(set, sym) __link_set_make_entry(set, sym) +#define __link_set_add_data(set, sym) __link_set_make_entry(set, sym) +#define __link_set_add_bss(set, sym) __link_set_make_entry(set, sym) +#define __link_set_add_text2(set, sym, n) __link_set_make_entry2(set, sym, n) +#define __link_set_add_rodata2(set, sym, n) __link_set_make_entry2(set, sym, n) +#define __link_set_add_data2(set, sym, n) __link_set_make_entry2(set, sym, n) +#define __link_set_add_bss2(set, sym, n) __link_set_make_entry2(set, sym, n) + +#define __link_set_decl(set, ptype) \ + extern ptype * const __start_link_set_##set[]; \ + extern ptype * const __stop_link_set_##set[] \ + +#define __link_set_start(set) (__start_link_set_##set) +#define __link_set_end(set) (__stop_link_set_##set) + +#define __link_set_count(set) \ + (__link_set_end(set) - __link_set_start(set)) + +#endif /* !_SYS_CDEFS_ELF_H_ */ diff --git a/cpukit/libdl/include/sys/exec_elf.h b/cpukit/libdl/include/sys/exec_elf.h new file mode 100644 index 0000000000..08da7e809e --- /dev/null +++ b/cpukit/libdl/include/sys/exec_elf.h @@ -0,0 +1,1097 @@ +/* $NetBSD: exec_elf.h,v 1.102 2010/03/01 11:27:29 skrll Exp $ */ + +/*- + * Copyright (c) 1994 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_EXEC_ELF_H_ +#define _SYS_EXEC_ELF_H_ + +/* + * The current ELF ABI specification is available at: + * http://www.sco.com/developers/gabi/ + * + * Current header definitions are in: + * http://www.sco.com/developers/gabi/latest/ch4.eheader.html + */ + +#if defined(_KERNEL) || defined(_STANDALONE) +#include <sys/types.h> +#else +#include <inttypes.h> +#endif /* _KERNEL || _STANDALONE */ + +#if defined(ELFSIZE) +#define CONCAT(x,y) __CONCAT(x,y) +#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x))) +#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y)))) +#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE)) +#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x))) +#endif + +#if HAVE_NBTOOL_CONFIG_H +#include <nbinclude/machine/elf_machdep.h> +#else +#include <machine/elf_machdep.h> +#endif + +typedef uint8_t Elf_Byte; + +typedef uint32_t Elf32_Addr; +#define ELF32_FSZ_ADDR 4 +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_SOff; +#define ELF32_FSZ_OFF 4 +typedef int32_t Elf32_Sword; +#define ELF32_FSZ_SWORD 4 +typedef uint32_t Elf32_Word; +#define ELF32_FSZ_WORD 4 +typedef uint16_t Elf32_Half; +#define ELF32_FSZ_HALF 2 +typedef uint64_t Elf32_Lword; +#define ELF32_FSZ_LWORD 8 + +typedef uint64_t Elf64_Addr; +#define ELF64_FSZ_ADDR 8 +typedef uint64_t Elf64_Off; +typedef int64_t Elf64_SOff; +#define ELF64_FSZ_OFF 8 +typedef int32_t Elf64_Shalf; +#define ELF64_FSZ_SHALF 4 + +#ifndef ELF64_FSZ_SWORD +typedef int32_t Elf64_Sword; +#define ELF64_FSZ_SWORD 4 +#endif /* ELF64_FSZ_SWORD */ +#ifndef ELF64_FSZ_WORD +typedef uint32_t Elf64_Word; +#define ELF64_FSZ_WORD 4 +#endif /* ELF64_FSZ_WORD */ + +typedef int64_t Elf64_Sxword; +#define ELF64_FSZ_SXWORD 8 +typedef uint64_t Elf64_Xword; +#define ELF64_FSZ_XWORD 8 +typedef uint64_t Elf64_Lword; +#define ELF64_FSZ_LWORD 8 +typedef uint32_t Elf64_Half; +#define ELF64_FSZ_HALF 4 +typedef uint16_t Elf64_Quarter; +#define ELF64_FSZ_QUARTER 2 + +/* + * ELF Header + */ +#define ELF_NIDENT 16 + +typedef struct { + unsigned char e_ident[ELF_NIDENT]; /* Id bytes */ + Elf32_Half e_type; /* file type */ + Elf32_Half e_machine; /* machine type */ + Elf32_Word e_version; /* version number */ + Elf32_Addr e_entry; /* entry point */ + Elf32_Off e_phoff; /* Program hdr offset */ + Elf32_Off e_shoff; /* Section hdr offset */ + Elf32_Word e_flags; /* Processor flags */ + Elf32_Half e_ehsize; /* sizeof ehdr */ + Elf32_Half e_phentsize; /* Program header entry size */ + Elf32_Half e_phnum; /* Number of program headers */ + Elf32_Half e_shentsize; /* Section header entry size */ + Elf32_Half e_shnum; /* Number of section headers */ + Elf32_Half e_shstrndx; /* String table index */ +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[ELF_NIDENT]; /* Id bytes */ + Elf64_Quarter e_type; /* file type */ + Elf64_Quarter e_machine; /* machine type */ + Elf64_Half e_version; /* version number */ + Elf64_Addr e_entry; /* entry point */ + Elf64_Off e_phoff; /* Program hdr offset */ + Elf64_Off e_shoff; /* Section hdr offset */ + Elf64_Half e_flags; /* Processor flags */ + Elf64_Quarter e_ehsize; /* sizeof ehdr */ + Elf64_Quarter e_phentsize; /* Program header entry size */ + Elf64_Quarter e_phnum; /* Number of program headers */ + Elf64_Quarter e_shentsize; /* Section header entry size */ + Elf64_Quarter e_shnum; /* Number of section headers */ + Elf64_Quarter e_shstrndx; /* String table index */ +} Elf64_Ehdr; + +/* e_ident offsets */ +#define EI_MAG0 0 /* '\177' */ +#define EI_MAG1 1 /* 'E' */ +#define EI_MAG2 2 /* 'L' */ +#define EI_MAG3 3 /* 'F' */ +#define EI_CLASS 4 /* File class */ +#define EI_DATA 5 /* Data encoding */ +#define EI_VERSION 6 /* File version */ +#define EI_OSABI 7 /* Operating system/ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define EI_PAD 9 /* Start of padding bytes up to EI_NIDENT*/ +#define EI_NIDENT 16 /* First non-ident header byte */ + +/* e_ident[EI_MAG0,EI_MAG3] */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +/* e_ident[EI_CLASS] */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +/* e_ident[EI_DATA] */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement values, LSB first */ +#define ELFDATA2MSB 2 /* 2's complement values, MSB first */ + +/* e_ident[EI_VERSION] */ +#define EV_NONE 0 /* Invalid version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* e_ident[EI_OSABI] */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_OPENVMS 13 /* OpenVMS */ +#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ +#define ELFOSABI_AROS 15 /* Amiga Research OS */ +/* Unofficial OSABIs follow */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define ELFOSABI_NONE ELFOSABI_SYSV +#define ELFOSABI_AIX ELFOSABI_MONTEREY + +/* e_type */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 + +#define ET_LOOS 0xfe00 /* Operating system specific range */ +#define ET_HIOS 0xfeff +#define ET_LOPROC 0xff00 /* Processor-specific range */ +#define ET_HIPROC 0xffff + +/* e_machine */ +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 80486 */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS I Architecture */ +#define EM_S370 9 /* Amdahl UTS on System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS RS3000 Little-endian */ + /* 11-14 - Reserved */ +#define EM_RS6000 11 /* IBM RS/6000 XXX reserved */ +#define EM_PARISC 15 /* Hewlett-Packard PA-RISC */ +#define EM_NCUBE 16 /* NCube XXX reserved */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* 64-bit PowerPC */ + /* 22-35 - Reserved */ +#define EM_S390 22 /* System/390 XXX reserved */ +#define EM_V800 36 /* NEC V800 */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* Advanced RISC Machines ARM */ +#define EM_ALPHA 41 /* DIGITAL Alpha */ +#define EM_SH 42 /* Hitachi Super-H */ +#define EM_SPARCV9 43 /* SPARC Version 9 */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced Processor */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola MC68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator */ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embedded RISC processor */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Star*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronics ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ embedded family processor */ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ +#define EM_PDP10 64 /* Digital Equipment Corp. PDP-10 */ +#define EM_PDP11 65 /* Digital Equipment Corp. PDP-11 */ +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 bit microcontroller */ +#define EM_ST7 68 /* STMicroelectronics ST7 8-bit microcontroller */ +#define EM_68HC16 69 /* Motorola MC68HC16 Microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 Microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 Microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 Microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8-bit CPU */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded CPU */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP processor */ +#define EM_ZSP 79 /* LSI Logic's 16-bit DSP processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard's machine-independent format */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_VIDEOCORE 95 /* Alphamosaic VideoCore processor */ +#define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose Processor */ +#define EM_NS32K 97 /* National Semiconductor 32000 series */ +#define EM_TPC 98 /* Tenor Network TPC processor */ +#define EM_SNP1K 99 /* Trebia SNP 1000 processor */ +#define EM_ST200 100 /* STMicroelectronics ST200 microcontroller */ +#define EM_IP2K 101 /* Ubicom IP2xxx microcontroller family */ +#define EM_MAX 102 /* MAX processor */ +#define EM_CR 103 /* National Semiconductor CompactRISC micorprocessor */ +#define EM_F2MC16 104 /* Fujitsu F2MC16 */ +#define EM_MSP430 105 /* Texas Instruments MSP430 */ +#define EM_BLACKFIN 106 /* Analog Devices Blackfin DSP */ +#define EM_SE_C33 107 /* Seiko Epson S1C33 family */ +#define EM_SEP 108 /* Sharp embedded microprocessor */ +#define EM_ARCA 109 /* Arca RISC microprocessor */ +#define EM_UNICORE 110 /* UNICORE from PKU-Unity Ltd. and MPRC Peking University */ +#define EM_EXCESS 111 /* eXcess: 16/32/64-bit configurable embedded CPU */ +#define EM_DXP 112 /* Icera Semiconductor Inc. Deep Execution Processor */ +#define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */ +#define EM_CRX 114 /* National Semiconductor CRX */ +#define EM_XGATE 115 /* Motorola XGATE embedded processor */ +#define EM_C166 116 /* Infineon C16x/XC16x processor */ +#define EM_M16C 117 /* Renesas M16C series microprocessors */ +#define EM_DSPIC30F 118 /* Microchip Technology dsPIC30F Digital Signal Controller */ +#define EM_CE 119 /* Freescale Communication Engine RISC core */ +#define EM_M32C 120 /* Renesas M32C series microprocessors */ + +#define EM_LATTICEMICO32 138 /* RICS processor for Lattice FPGA architecture */ + +#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze 32-bit RISC soft processor core */ + +#define EM_MOXIE 0xFEED + +/* Unofficial machine types follow */ +#define EM_AVR32 6317 /* used by NetBSD/avr32 */ +#define EM_ALPHA_EXP 36902 /* used by NetBSD/alpha; obsolete */ +#define EM_NUM 36903 + +/* + * Program Header + */ +typedef struct { + Elf32_Word p_type; /* entry type */ + Elf32_Off p_offset; /* offset */ + Elf32_Addr p_vaddr; /* virtual address */ + Elf32_Addr p_paddr; /* physical address */ + Elf32_Word p_filesz; /* file size */ + Elf32_Word p_memsz; /* memory size */ + Elf32_Word p_flags; /* flags */ + Elf32_Word p_align; /* memory & file alignment */ +} Elf32_Phdr; + +typedef struct { + Elf64_Half p_type; /* entry type */ + Elf64_Half p_flags; /* flags */ + Elf64_Off p_offset; /* offset */ + Elf64_Addr p_vaddr; /* virtual address */ + Elf64_Addr p_paddr; /* physical address */ + Elf64_Xword p_filesz; /* file size */ + Elf64_Xword p_memsz; /* memory size */ + Elf64_Xword p_align; /* memory & file alignment */ +} Elf64_Phdr; + +/* p_type */ +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved, unspecified semantics */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_NUM 7 + +#define PT_LOOS 0x60000000 /* OS-specific range */ +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 /* Processor-specific range */ +#define PT_HIPROC 0x7fffffff + +#define PT_MIPS_REGINFO 0x70000000 + +/* p_flags */ +#define PF_R 0x4 /* Segment is readable */ +#define PF_W 0x2 /* Segment is writable */ +#define PF_X 0x1 /* Segment is executable */ + +#define PF_MASKOS 0x0ff00000 /* Operating system specific values */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific values */ + +/* Extended program header index. */ +#define PN_XNUM 0xffff + +/* + * Section Headers + */ +typedef struct { + Elf32_Word sh_name; /* section name (.shstrtab index) */ + Elf32_Word sh_type; /* section type */ + Elf32_Word sh_flags; /* section flags */ + Elf32_Addr sh_addr; /* virtual address */ + Elf32_Off sh_offset; /* file offset */ + Elf32_Word sh_size; /* section size */ + Elf32_Word sh_link; /* link to another */ + Elf32_Word sh_info; /* misc info */ + Elf32_Word sh_addralign; /* memory alignment */ + Elf32_Word sh_entsize; /* table entry size */ +} Elf32_Shdr; + +typedef struct { + Elf64_Half sh_name; /* section name (.shstrtab index) */ + Elf64_Half sh_type; /* section type */ + Elf64_Xword sh_flags; /* section flags */ + Elf64_Addr sh_addr; /* virtual address */ + Elf64_Off sh_offset; /* file offset */ + Elf64_Xword sh_size; /* section size */ + Elf64_Half sh_link; /* link to another */ + Elf64_Half sh_info; /* misc info */ + Elf64_Xword sh_addralign; /* memory alignment */ + Elf64_Xword sh_entsize; /* table entry size */ +} Elf64_Shdr; + +/* sh_type */ +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program information */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation information w/ addend */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Auxiliary information */ +#define SHT_NOBITS 8 /* No space allocated in file image */ +#define SHT_REL 9 /* Relocation information w/o addend */ +#define SHT_SHLIB 10 /* Reserved, unspecified semantics */ +#define SHT_DYNSYM 11 /* Symbol table for dynamic linker */ +#define SHT_INIT_ARRAY 14 /* Initialization function pointers */ +#define SHT_FINI_ARRAY 15 /* Termination function pointers */ +#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX) */ +#define SHT_NUM 19 + +#define SHT_LOOS 0x60000000 /* Operating system specific range */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_SUNW_verdef 0x6ffffffd /* Versions defined by file */ +#define SHT_GNU_verdef SHT_SUNW_verdef +#define SHT_SUNW_verneed 0x6ffffffe /* Versions needed by file */ +#define SHT_GNU_verneed SHT_SUNW_verneed +#define SHT_SUNW_versym 0x6fffffff /* Symbol versions */ +#define SHT_GNU_versym SHT_SUNW_versym +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 /* Processor-specific range */ +#define SHT_AMD64_UNWIND 0x70000001 /* unwind information */ +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 /* Application-specific range */ +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 /* Section contains writable data */ +#define SHF_ALLOC 0x2 /* Section occupies memory */ +#define SHF_EXECINSTR 0x4 /* Section contains executable insns */ + +#define SHF_MASKOS 0x0f000000 /* Operating system specific values */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific values */ + +/* + * Symbol Table + */ +typedef struct { + Elf32_Word st_name; /* Symbol name (.strtab index) */ + Elf32_Word st_value; /* value of symbol */ + Elf32_Word st_size; /* size of symbol */ + Elf_Byte st_info; /* type / binding attrs */ + Elf_Byte st_other; /* unused */ + Elf32_Half st_shndx; /* section index of symbol */ +} Elf32_Sym; + +typedef struct { + Elf64_Half st_name; /* Symbol name (.strtab index) */ + Elf_Byte st_info; /* type / binding attrs */ + Elf_Byte st_other; /* unused */ + Elf64_Quarter st_shndx; /* section index of symbol */ + Elf64_Addr st_value; /* value of symbol */ + Elf64_Xword st_size; /* size of symbol */ +} Elf64_Sym; + +/* Symbol Table index of the undefined symbol */ +#define ELF_SYM_UNDEFINED 0 + +#define STN_UNDEF 0 /* undefined index */ + +/* st_info: Symbol Bindings */ +#define STB_LOCAL 0 /* local symbol */ +#define STB_GLOBAL 1 /* global symbol */ +#define STB_WEAK 2 /* weakly defined global symbol */ +#define STB_NUM 3 + +#define STB_LOOS 10 /* Operating system specific range */ +#define STB_HIOS 12 +#define STB_LOPROC 13 /* Processor-specific range */ +#define STB_HIPROC 15 + +/* st_info: Symbol Types */ +#define STT_NOTYPE 0 /* Type not specified */ +#define STT_OBJECT 1 /* Associated with a data object */ +#define STT_FUNC 2 /* Associated with a function */ +#define STT_SECTION 3 /* Associated with a section */ +#define STT_FILE 4 /* Associated with a file name */ +#define STT_COMMON 5 /* Uninitialised common block */ +#define STT_TLS 6 /* Thread local data object */ +#define STT_NUM 7 + +#define STT_LOOS 10 /* Operating system specific range */ +#define STT_HIOS 12 +#define STT_LOPROC 13 /* Processor-specific range */ +#define STT_HIPROC 15 + +/* st_other: Visibility Types */ +#define STV_DEFAULT 0 /* use binding type */ +#define STV_INTERNAL 1 /* not referenced from outside */ +#define STV_HIDDEN 2 /* not visible, may be used via ptr */ +#define STV_PROTECTED 3 /* visible, not preemptible */ +#define STV_EXPORTED 4 +#define STV_SINGLETON 5 +#define STV_ELIMINATE 6 + +/* st_info/st_other utility macros */ +#define ELF_ST_BIND(info) ((uint32_t)(info) >> 4) +#define ELF_ST_TYPE(info) ((uint32_t)(info) & 0xf) +#define ELF_ST_INFO(bind,type) ((Elf_Byte)(((bind) << 4) | \ + ((type) & 0xf))) +#define ELF_ST_VISIBILITY(other) ((uint32_t)(other) & 3) + +/* + * Special section indexes + */ +#define SHN_UNDEF 0 /* Undefined section */ + +#define SHN_LORESERVE 0xff00 /* Reserved range */ +#define SHN_ABS 0xfff1 /* Absolute symbols */ +#define SHN_COMMON 0xfff2 /* Common symbols */ +#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere */ +#define SHN_HIRESERVE 0xffff + +#define SHN_LOPROC 0xff00 /* Processor-specific range */ +#define SHN_HIPROC 0xff1f +#define SHN_LOOS 0xff20 /* Operating system specific range */ +#define SHN_HIOS 0xff3f + +#define SHN_MIPS_ACOMMON 0xff00 +#define SHN_MIPS_TEXT 0xff01 +#define SHN_MIPS_DATA 0xff02 +#define SHN_MIPS_SCOMMON 0xff03 + +/* + * Relocation Entries + */ +typedef struct { + Elf32_Word r_offset; /* where to do it */ + Elf32_Word r_info; /* index & type of relocation */ +} Elf32_Rel; + +typedef struct { + Elf32_Word r_offset; /* where to do it */ + Elf32_Word r_info; /* index & type of relocation */ + Elf32_Sword r_addend; /* adjustment value */ +} Elf32_Rela; + +/* r_info utility macros */ +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((info) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + +typedef struct { + Elf64_Addr r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ +} Elf64_Rel; + +typedef struct { + Elf64_Addr r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ + Elf64_Sxword r_addend; /* adjustment value */ +} Elf64_Rela; + +/* r_info utility macros */ +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info) & 0xffffffff) +#define ELF64_R_INFO(sym,type) (((sym) << 32) + (type)) + +/* + * Move entries + */ +typedef struct { + Elf32_Lword m_value; /* symbol value */ + Elf32_Word m_info; /* size + index */ + Elf32_Word m_poffset; /* symbol offset */ + Elf32_Half m_repeat; /* repeat count */ + Elf32_Half m_stride; /* stride info */ +} Elf32_Move; + +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) (info) & 0xff) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size)) + +typedef struct { + Elf64_Lword m_value; /* symbol value */ + Elf64_Xword m_info; /* size + index */ + Elf64_Xword m_poffset; /* symbol offset */ + Elf64_Half m_repeat; /* repeat count */ + Elf64_Half m_stride; /* stride info */ +} Elf64_Move; + +#define ELF64_M_SYM(info) ((info) >> 8) +#define ELF64_M_SIZE(info) (info) & 0xff) +#define ELF64_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size)) + +/* + * Hardware/software capabilities entry + */ +typedef struct { + Elf32_Word c_tag; /* entry tag value */ + union { + Elf32_Addr c_ptr; + Elf32_Word c_val; + } c_un; +} Elf32_Cap; + +typedef struct { + Elf64_Xword c_tag; /* entry tag value */ + union { + Elf64_Addr c_ptr; + Elf64_Xword c_val; + } c_un; +} Elf64_Cap; + +/* + * Dynamic Section structure array + */ +typedef struct { + Elf32_Word d_tag; /* entry tag value */ + union { + Elf32_Addr d_ptr; + Elf32_Word d_val; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Xword d_tag; /* entry tag value */ + union { + Elf64_Addr d_ptr; + Elf64_Xword d_val; + } d_un; +} Elf64_Dyn; + +/* d_tag */ +#define DT_NULL 0 /* Marks end of dynamic array */ +#define DT_NEEDED 1 /* Name of needed library (DT_STRTAB offset) */ +#define DT_PLTRELSZ 2 /* Size, in bytes, of relocations in PLT */ +#define DT_PLTGOT 3 /* Address of PLT and/or GOT */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocation table */ +#define DT_RELASZ 8 /* Size, in bytes, of DT_RELA table */ +#define DT_RELAENT 9 /* Size, in bytes, of one DT_RELA entry */ +#define DT_STRSZ 10 /* Size, in bytes, of DT_STRTAB table */ +#define DT_SYMENT 11 /* Size, in bytes, of one DT_SYMTAB entry */ +#define DT_INIT 12 /* Address of initialization function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Shared object name (DT_STRTAB offset) */ +#define DT_RPATH 15 /* Library search path (DT_STRTAB offset) */ +#define DT_SYMBOLIC 16 /* Start symbol search within local object */ +#define DT_REL 17 /* Address of Rel relocation table */ +#define DT_RELSZ 18 /* Size, in bytes, of DT_REL table */ +#define DT_RELENT 19 /* Size, in bytes, of one DT_REL entry */ +#define DT_PLTREL 20 /* Type of PLT relocation entries */ +#define DT_DEBUG 21 /* Used for debugging; unspecified */ +#define DT_TEXTREL 22 /* Relocations might modify non-writable seg */ +#define DT_JMPREL 23 /* Address of relocations associated with PLT */ +#define DT_BIND_NOW 24 /* Process all relocations at load-time */ +#define DT_INIT_ARRAY 25 /* Address of initialization function array */ +#define DT_FINI_ARRAY 26 /* Size, in bytes, of DT_INIT_ARRAY array */ +#define DT_INIT_ARRAYSZ 27 /* Address of termination function array */ +#define DT_FINI_ARRAYSZ 28 /* Size, in bytes, of DT_FINI_ARRAY array*/ +#define DT_NUM 29 + +#define DT_LOOS 0x60000000 /* Operating system specific range */ +#define DT_VERSYM 0x6ffffff0 /* Symbol versions */ +#define DT_FLAGS_1 0x6ffffffb /* ELF dynamic flags */ +#define DT_VERDEF 0x6ffffffc /* Versions defined by file */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of versions defined by file */ +#define DT_VERNEED 0x6ffffffe /* Versions needed by file */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of versions needed by file */ +#define DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 /* Processor-specific range */ +#define DT_HIPROC 0x7fffffff + +/* Flag values for DT_FLAGS_1 (incomplete) */ +#define DF_1_INITFIRST 0x00000020 /* Object's init/fini take priority */ + +/* + * Auxiliary Vectors + */ +typedef struct { + Elf32_Word a_type; /* 32-bit id */ + Elf32_Word a_v; /* 32-bit id */ +} Aux32Info; + +typedef struct { + Elf64_Half a_type; /* 32-bit id */ + Elf64_Xword a_v; /* 64-bit id */ +} Aux64Info; + +/* a_type */ +#define AT_NULL 0 /* Marks end of array */ +#define AT_IGNORE 1 /* No meaning, a_un is undefined */ +#define AT_EXECFD 2 /* Open file descriptor of object file */ +#define AT_PHDR 3 /* &phdr[0] */ +#define AT_PHENT 4 /* sizeof(phdr[0]) */ +#define AT_PHNUM 5 /* # phdr entries */ +#define AT_PAGESZ 6 /* PAGESIZE */ +#define AT_BASE 7 /* Interpreter base addr */ +#define AT_FLAGS 8 /* Processor flags */ +#define AT_ENTRY 9 /* Entry address of executable */ +#define AT_DCACHEBSIZE 10 /* Data cache block size */ +#define AT_ICACHEBSIZE 11 /* Instruction cache block size */ +#define AT_UCACHEBSIZE 12 /* Unified cache block size */ + + /* Vendor specific */ +#define AT_MIPS_NOTELF 10 /* XXX a_val != 0 -> MIPS XCOFF executable */ + +#define AT_EUID 2000 /* euid (solaris compatible numbers) */ +#define AT_RUID 2001 /* ruid (solaris compatible numbers) */ +#define AT_EGID 2002 /* egid (solaris compatible numbers) */ +#define AT_RGID 2003 /* rgid (solaris compatible numbers) */ + + /* Solaris kernel specific */ +#define AT_SUN_LDELF 2004 /* dynamic linker's ELF header */ +#define AT_SUN_LDSHDR 2005 /* dynamic linker's section header */ +#define AT_SUN_LDNAME 2006 /* dynamic linker's name */ +#define AT_SUN_LPGSIZE 2007 /* large pagesize */ + + /* Other information */ +#define AT_SUN_PLATFORM 2008 /* sysinfo(SI_PLATFORM) */ +#define AT_SUN_HWCAP 2009 /* process hardware capabilities */ +#define AT_SUN_IFLUSH 2010 /* do we need to flush the instruction cache? */ +#define AT_SUN_CPU 2011 /* CPU name */ + /* ibcs2 emulation band aid */ +#define AT_SUN_EMUL_ENTRY 2012 /* coff entry point */ +#define AT_SUN_EMUL_EXECFD 2013 /* coff file descriptor */ + /* Executable's fully resolved name */ +#define AT_SUN_EXECNAME 2014 + +/* + * Note Headers + */ +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Half n_namesz; + Elf64_Half n_descsz; + Elf64_Half n_type; +} Elf64_Nhdr; + +#define ELF_NOTE_TYPE_ABI_TAG 1 + +/* GNU-specific note name and description sizes */ +#define ELF_NOTE_ABI_NAMESZ 4 +#define ELF_NOTE_ABI_DESCSZ 16 +/* GNU-specific note name */ +#define ELF_NOTE_ABI_NAME "GNU\0" + +/* GNU-specific OS/version value stuff */ +#define ELF_NOTE_ABI_OS_LINUX 0 +#define ELF_NOTE_ABI_OS_HURD 1 +#define ELF_NOTE_ABI_OS_SOLARIS 2 + +/* NetBSD-specific note type: Emulation name. desc is emul name string. */ +#define ELF_NOTE_TYPE_NETBSD_TAG 1 +/* NetBSD-specific note name and description sizes */ +#define ELF_NOTE_NETBSD_NAMESZ 7 +#define ELF_NOTE_NETBSD_DESCSZ 4 +/* NetBSD-specific note name */ +#define ELF_NOTE_NETBSD_NAME "NetBSD\0\0" + +/* NetBSD-specific note type: Checksum. There should be 1 NOTE per PT_LOAD + section. desc is a tuple of <phnum>(16),<chk-type>(16),<chk-value>. */ +#define ELF_NOTE_TYPE_CHECKSUM_TAG 2 +#define ELF_NOTE_CHECKSUM_CRC32 1 +#define ELF_NOTE_CHECKSUM_MD5 2 +#define ELF_NOTE_CHECKSUM_SHA1 3 +#define ELF_NOTE_CHECKSUM_SHA256 4 + +/* NetBSD-specific note type: PaX. There should be 1 NOTE per executable. + section. desc is a 32 bit bitmask */ +#define ELF_NOTE_TYPE_PAX_TAG 3 +#define ELF_NOTE_PAX_MPROTECT 0x01 /* Force enable Mprotect */ +#define ELF_NOTE_PAX_NOMPROTECT 0x02 /* Force disable Mprotect */ +#define ELF_NOTE_PAX_GUARD 0x04 /* Force enable Segvguard */ +#define ELF_NOTE_PAX_NOGUARD 0x08 /* Force disable Servguard */ +#define ELF_NOTE_PAX_ASLR 0x10 /* Force enable ASLR */ +#define ELF_NOTE_PAX_NOASLR 0x20 /* Force disable ASLR */ +#define ELF_NOTE_PAX_NAMESZ 4 +#define ELF_NOTE_PAX_NAME "PaX\0" +#define ELF_NOTE_PAX_DESCSZ 4 + +/* + * NetBSD-specific core file information. + * + * NetBSD ELF core files use notes to provide information about + * the process's state. The note name is "NetBSD-CORE" for + * information that is global to the process, and "NetBSD-CORE@nn", + * where "nn" is the lwpid of the LWP that the information belongs + * to (such as register state). + * + * We use the following note identifiers: + * + * ELF_NOTE_NETBSD_CORE_PROCINFO + * Note is a "netbsd_elfcore_procinfo" structure. + * + * We also use ptrace(2) request numbers (the ones that exist in + * machine-dependent space) to identify register info notes. The + * info in such notes is in the same format that ptrace(2) would + * export that information. + * + * Please try to keep the members of this structure nicely aligned, + * and if you add elements, add them to the end and bump the version. + */ + +#define ELF_NOTE_NETBSD_CORE_NAME "NetBSD-CORE" + +#define ELF_NOTE_NETBSD_CORE_PROCINFO 1 + +#define NETBSD_ELFCORE_PROCINFO_VERSION 1 + +struct netbsd_elfcore_procinfo { + /* Version 1 fields start here. */ + uint32_t cpi_version; /* netbsd_elfcore_procinfo version */ + uint32_t cpi_cpisize; /* sizeof(netbsd_elfcore_procinfo) */ + uint32_t cpi_signo; /* killing signal */ + uint32_t cpi_sigcode; /* signal code */ + uint32_t cpi_sigpend[4]; /* pending signals */ + uint32_t cpi_sigmask[4]; /* blocked signals */ + uint32_t cpi_sigignore[4];/* blocked signals */ + uint32_t cpi_sigcatch[4];/* blocked signals */ + int32_t cpi_pid; /* process ID */ + int32_t cpi_ppid; /* parent process ID */ + int32_t cpi_pgrp; /* process group ID */ + int32_t cpi_sid; /* session ID */ + uint32_t cpi_ruid; /* real user ID */ + uint32_t cpi_euid; /* effective user ID */ + uint32_t cpi_svuid; /* saved user ID */ + uint32_t cpi_rgid; /* real group ID */ + uint32_t cpi_egid; /* effective group ID */ + uint32_t cpi_svgid; /* saved group ID */ + uint32_t cpi_nlwps; /* number of LWPs */ + int8_t cpi_name[32]; /* copy of p->p_comm */ + /* Add version 2 fields below here. */ + int32_t cpi_siglwp; /* LWP target of killing signal */ +}; + +#if defined(ELFSIZE) && (ELFSIZE == 32) +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Rel Elf32_Rel +#define Elf_Rela Elf32_Rela +#define Elf_Dyn Elf32_Dyn +#define Elf_Word Elf32_Word +#define Elf_Sword Elf32_Sword +#define Elf_Addr Elf32_Addr +#define Elf_Off Elf32_Off +#define Elf_SOff Elf32_SOff +#define Elf_Nhdr Elf32_Nhdr + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELFCLASS ELFCLASS32 + +#define AuxInfo Aux32Info +#elif defined(ELFSIZE) && (ELFSIZE == 64) +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Rel Elf64_Rel +#define Elf_Rela Elf64_Rela +#define Elf_Dyn Elf64_Dyn +#define Elf_Word Elf64_Word +#define Elf_Sword Elf64_Sword +#define Elf_Addr Elf64_Addr +#define Elf_Off Elf64_Off +#define Elf_SOff Elf64_SOff +#define Elf_Nhdr Elf64_Nhdr + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELFCLASS ELFCLASS64 + +#define AuxInfo Aux64Info +#endif + +#define ELF32_ST_BIND(info) ELF_ST_BIND(info) +#define ELF32_ST_TYPE(info) ELF_ST_TYPE(info) +#define ELF32_ST_INFO(bind,type) ELF_ST_INFO(bind,type) +#define ELF32_ST_VISIBILITY(other) ELF_ST_VISIBILITY(other) + +#define ELF64_ST_BIND(info) ELF_ST_BIND(info) +#define ELF64_ST_TYPE(info) ELF_ST_TYPE(info) +#define ELF64_ST_INFO(bind,type) ELF_ST_INFO(bind,type) +#define ELF64_ST_VISIBILITY(other) ELF_ST_VISIBILITY(other) + +typedef struct { + Elf32_Half si_boundto; /* direct bindings - symbol bound to */ + Elf32_Half si_flags; /* per symbol flags */ +} Elf32_Syminfo; + +typedef struct { + Elf64_Half si_boundto; /* direct bindings - symbol bound to */ + Elf64_Half si_flags; /* per symbol flags */ +} Elf64_Syminfo; + +#define SYMINFO_FLG_DIRECT 0x0001 /* symbol ref has direct association + to object containing definition */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* ignored - see SYMINFO_FLG_FILTER */ +#define SYMINFO_FLG_COPY 0x0004 /* symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* object containing defn should be + lazily-loaded */ +#define SYMINFO_FLG_DIRECTBIND 0x0010 /* ref should be bound directly to + object containing definition */ +#define SYMINFO_FLG_NOEXTDIRECT 0x0020 /* don't let an external reference + directly bind to this symbol */ +#define SYMINFO_FLG_FILTER 0x0002 /* symbol ref is associated to a */ +#define SYMINFO_FLG_AUXILIARY 0x0040 /* standard or auxiliary filter */ + +#define SYMINFO_BT_SELF 0xffff /* symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* symbol bound to parent */ +#define SYMINFO_BT_NONE 0xfffd /* no special symbol binding */ +#define SYMINFO_BT_EXTERN 0xfffc /* symbol defined as external */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* beginning of reserved entries */ + +#define SYMINFO_NONE 0 /* Syminfo version */ +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + +/* + * These constants are used for Elf32_Verdef struct's version number. + */ +#define VER_DEF_NONE 0 +#define VER_DEF_CURRENT 1 + +/* + * These constants are used for Elf32_Verdef struct's vd_flags. + */ +#define VER_FLG_BASE 0x1 +#define VER_FLG_WEAK 0x2 + +/* + * These are used in an Elf32_Versym field. + */ +#define VER_NDX_LOCAL 0 +#define VER_NDX_GLOBAL 1 + +/* + * These constants are used for Elf32_Verneed struct's version number. + */ +#define VER_NEED_NONE 0 +#define VER_NEED_CURRENT 1 + +/* + * GNU Extension hidding symb + */ +#define VERSYM_HIDDEN 0x8000 +#define VERSYM_VERSION 0x7fff + +#define ELF_VER_CHR '@' + +/* + * These are current size independent. + */ + +typedef struct { + Elf32_Half vd_version; /* version number of structure */ + Elf32_Half vd_flags; /* flags (VER_FLG_*) */ + Elf32_Half vd_ndx; /* version index */ + Elf32_Half vd_cnt; /* number of verdaux entries */ + Elf32_Word vd_hash; /* hash of name */ + Elf32_Word vd_aux; /* offset to verdaux entries */ + Elf32_Word vd_next; /* offset to next verdef */ +} Elf32_Verdef; +typedef Elf32_Verdef Elf64_Verdef; + +typedef struct { + Elf32_Word vda_name; /* string table offset of name */ + Elf32_Word vda_next; /* offset to verdaux */ +} Elf32_Verdaux; +typedef Elf32_Verdaux Elf64_Verdaux; + +typedef struct { + Elf32_Half vn_version; /* version number of structure */ + Elf32_Half vn_cnt; /* number of vernaux entries */ + Elf32_Word vn_file; /* string table offset of library name*/ + Elf32_Word vn_aux; /* offset to vernaux entries */ + Elf32_Word vn_next; /* offset to next verneed */ +} Elf32_Verneed; +typedef Elf32_Verneed Elf64_Verneed; + +typedef struct { + Elf32_Word vna_hash; /* Hash of dependency name */ + Elf32_Half vna_flags; /* flags (VER_FLG_*) */ + Elf32_Half vna_other; /* unused */ + Elf32_Word vna_name; /* string table offset to version name*/ + Elf32_Word vna_next; /* offset to next vernaux */ +} Elf32_Vernaux; +typedef Elf32_Vernaux Elf64_Vernaux; + +typedef struct { + Elf32_Half vs_vers; +} Elf32_Versym; +typedef Elf32_Versym Elf64_Versym; + +#ifdef _KERNEL + +#define ELF_AUX_ENTRIES 14 /* Max size of aux array passed to loader */ +#define ELF32_NO_ADDR (~(Elf32_Addr)0) /* Indicates addr. not yet filled in */ +#define ELF32_LINK_ADDR ((Elf32_Addr)-2) /* advises to use link address */ +#define ELF64_NO_ADDR (~(Elf64_Addr)0) /* Indicates addr. not yet filled in */ +#define ELF64_LINK_ADDR ((Elf64_Addr)-2) /* advises to use link address */ + +#if defined(ELFSIZE) && (ELFSIZE == 64) +#define ELF_NO_ADDR ELF64_NO_ADDR +#define ELF_LINK_ADDR ELF64_LINK_ADDR +#elif defined(ELFSIZE) && (ELFSIZE == 32) +#define ELF_NO_ADDR ELF32_NO_ADDR +#define ELF_LINK_ADDR ELF32_LINK_ADDR +#endif + +#ifndef ELF32_EHDR_FLAGS_OK +#define ELF32_EHDR_FLAGS_OK(eh) 1 +#endif + +#ifndef ELF64_EHDR_FLAGS_OK +#define ELF64_EHDR_FLAGS_OK(eh) 1 +#endif + +#if defined(ELFSIZE) && (ELFSIZE == 64) +#define ELF_EHDR_FLAGS_OK(eh) ELF64_EHDR_FLAGS_OK(eh) +#else +#define ELF_EHDR_FLAGS_OK(eh) ELF32_EHDR_FLAGS_OK(eh) +#endif + +#if defined(ELFSIZE) +struct elf_args { + Elf_Addr arg_entry; /* program entry point */ + Elf_Addr arg_interp; /* Interpreter load address */ + Elf_Addr arg_phaddr; /* program header address */ + Elf_Addr arg_phentsize; /* Size of program header */ + Elf_Addr arg_phnum; /* Number of program headers */ +}; +#endif + +#ifdef _KERNEL_OPT +#include "opt_execfmt.h" +#endif + +#ifdef EXEC_ELF32 +int exec_elf32_makecmds(struct lwp *, struct exec_package *); +int elf32_copyargs(struct lwp *, struct exec_package *, + struct ps_strings *, char **, void *); + +int coredump_elf32(struct lwp *, void *); +int coredump_writenote_elf32(struct proc *, void *, Elf32_Nhdr *, + const char *, void *); + +int elf32_check_header(Elf32_Ehdr *, int); +#endif + +#ifdef EXEC_ELF64 +int exec_elf64_makecmds(struct lwp *, struct exec_package *); +int elf64_copyargs(struct lwp *, struct exec_package *, + struct ps_strings *, char **, void *); + +int coredump_elf64(struct lwp *, void *); +int coredump_writenote_elf64(struct proc *, void *, Elf64_Nhdr *, + const char *, void *); + +int elf64_check_header(Elf64_Ehdr *, int); +#endif + +#endif /* _KERNEL */ + +#endif /* !_SYS_EXEC_ELF_H_ */ diff --git a/cpukit/libdl/preinstall.am b/cpukit/libdl/preinstall.am new file mode 100644 index 0000000000..dba6cc4d81 --- /dev/null +++ b/cpukit/libdl/preinstall.am @@ -0,0 +1,7 @@ +## Automatically generated by ampolish3 - Do not edit + +if AMPOLISH3 +$(srcdir)/preinstall.am: Makefile.am + $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am +endif + diff --git a/cpukit/libdl/rap-shell.c b/cpukit/libdl/rap-shell.c new file mode 100644 index 0000000000..664f3a3055 --- /dev/null +++ b/cpukit/libdl/rap-shell.c @@ -0,0 +1,106 @@ +/* + * COPYRIGHT (c) 2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Application Loader. + * + * Shell command wrappers for the RTEMS Application loader. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <rtems/rtl/rap.h> +#include <rtems/rtl/rap-shell.h> + +static void +shell_rap_command_help (void) +{ + printf ("usage: rap [cmd] [arg]\n" \ + "Commands and options:\n" \ + "ls: List the loaded applications (also list)\n" \ + "ld: Load an application (also load)\n" \ + "un: Unload an application (also unload)\n"); +} + +static void +shell_rap_get_error (const char* what) +{ + char message[64]; + int error; + error = rtems_rap_get_error (message, sizeof (message)); + printf ("error: %s: (%d) %s\n", what, error, message); +} + +static bool +shell_rap_list_handler (void* handle) +{ + printf (" %-10p %-10p %-s\n", + handle, rtems_rap_dl_handle (handle), rtems_rap_name (handle)); + return true; +} + +static int +shell_rap_list (int argc, char* argv[]) +{ + printf (" App DL Handle Name\n"); + return rtems_rap_iterate (shell_rap_list_handler) ? 0 : 1; +} + +static int +shell_rap_load (int argc, char* argv[]) +{ + int r = 0; + if (argc == 0) + { + printf ("error: no application name\n"); + return 0; + } + if (rtems_rap_load (argv[0], 0, argc - 1, (const char**) (argv + 1))) + printf ("%s loaded\n", argv[0]); + else + { + r = 1; + shell_rap_get_error ("loading"); + } + return r; +} + +int +shell_rap (int argc, char* argv[]) +{ + if (argc == 1) + { + shell_rap_command_help (); + return 0; + } + + if ((strcmp (argv[1], "ls") == 0) || + (strcmp (argv[1], "list") == 0)) + { + return shell_rap_list (argc - 2, argv + 2); + } + else if ((strcmp (argv[1], "ld") == 0) || + (strcmp (argv[1], "load") == 0)) + { + return shell_rap_load (argc - 2, argv + 2); + } + + printf ("error: invalid command: %s\n", argv[1]); + return 0; +} + diff --git a/cpukit/libdl/rap-shell.h b/cpukit/libdl/rap-shell.h new file mode 100644 index 0000000000..c32529d6da --- /dev/null +++ b/cpukit/libdl/rap-shell.h @@ -0,0 +1,14 @@ +/* + * COPYRIGHT (c) 2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#if !defined(_RAP_SHELL_H_) +#define _RAP_SHELL_H_ + +int shell_rap (int argc, char* argv[]); + +#endif diff --git a/cpukit/libdl/rap.c b/cpukit/libdl/rap.c new file mode 100644 index 0000000000..8dec41e416 --- /dev/null +++ b/cpukit/libdl/rap.c @@ -0,0 +1,484 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rap + * + * @brief RTEMS Application Loader + * + * This is the RAP implementation. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <rtems/libio_.h> + +#include <dlfcn.h> +#include <rtems/rtl/rap.h> +#include <rtems/rtl/rtl.h> + +#include "rtl-find-file.h" + +/** + * The global RAP data. This structure is allocated on the heap when the first + * call to location an application and is never released. + */ +typedef struct rtems_rap_data_s +{ + rtems_id lock; /**< The RAP lock id */ + rtems_chain_control apps; /**< List if loaded application. */ + int last_errno; /**< Last error number. */ + char last_error[64]; /**< Last error string. */ +} rtems_rap_data_t; + +/** + * The RAP file data. This structure is allocated on the heap when a file is + * loaded. + */ +typedef struct rtems_rap_app_s +{ + rtems_chain_node node; /**< The node's link in the chain. */ + const char* name; /**< The file name */ + void* handle; /**< The dlopen handle. */ +} rtems_rap_app_t; + +/** + * Semaphore configuration to create a mutex. + */ +#define RTEMS_MUTEX_ATTRIBS \ + (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \ + RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL) + +/** + * RTL entry. + */ +#if (RTL_GLUE(__USER_LABEL_PREFIX__, 1) == RTL_GLUE(_, 1)) + #define RTL_ENTRY_POINT "_rtems" +#else + #define RTL_ENTRY_POINT "rtems" +#endif + +/** + * Static RAP data is returned to the user when the loader is locked. + */ +static rtems_rap_data_t rap_; + +/** + * Verbose level for the RAP loader. + */ +static bool rap_verbose; + +/** + * RAP entry call signature. + */ +typedef int (*rtems_rap_entry_t)(int argc, const char* argv[]); + +/** + * Forward decl. + */ +static bool rtems_rap_unlock (void); + +static bool +rtems_rap_data_init (void) +{ + /* + * Lock the RAP. We only create a lock if a call is made. First we test if a + * lock is present. If one is present we lock it. If not the libio lock is + * locked and we then test the lock again. If not present we create the lock + * then release libio lock. + */ + if (!rap_.lock) + { + rtems_libio_lock (); + + if (!rap_.lock) + { + rtems_status_code sc; + rtems_id lock; + + /* + * Create the RAP lock. + */ + sc = rtems_semaphore_create (rtems_build_name ('R', 'A', 'P', '_'), + 1, RTEMS_MUTEX_ATTRIBS, + RTEMS_NO_PRIORITY, &lock); + if (sc != RTEMS_SUCCESSFUL) + return false; + + sc = rtems_semaphore_obtain (lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + { + rtems_semaphore_delete (lock); + return false; + } + + rap_.lock = lock; + + /* + * Initialise the objects list and create any required services. + */ + rtems_chain_initialize_empty (&rap_.apps); + } + + rtems_libio_unlock (); + + rtems_rap_unlock (); + } + return true; +} + +static rtems_rap_data_t* +rtems_rap_lock (void) +{ + rtems_status_code sc; + + if (!rtems_rap_data_init ()) + return NULL; + + sc = rtems_semaphore_obtain (rap_.lock, + RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + { + errno = EINVAL; + return NULL; + } + + return &rap_; +} + +static bool +rtems_rap_unlock (void) +{ + /* + * Not sure any error should be returned or an assert. + */ + rtems_status_code sc; + sc = rtems_semaphore_release (rap_.lock); + if ((sc != RTEMS_SUCCESSFUL) && (errno == 0)) + { + errno = EINVAL; + return false; + } + return true; +} + +static rtems_rap_app_t* +rtems_rap_check_handle (void* handle) +{ + rtems_rap_app_t* app; + rtems_chain_node* node; + + app = handle; + node = rtems_chain_first (&rap_.apps); + + while (!rtems_chain_is_tail (&rap_.apps, node)) + { + rtems_rap_app_t* check = (rtems_rap_app_t*) node; + if (check == app) + return app; + node = rtems_chain_next (node); + } + + return NULL; +} + +static rtems_rap_app_t* +rtems_rap_app_alloc (void) +{ + rtems_rap_app_t* app = malloc (sizeof (rtems_rap_app_t)); + memset (app, 0, sizeof (rtems_rap_app_t)); + rtems_chain_append (&rap_.apps, &app->node); + return app; +} + +static void +rtems_rap_app_free (rtems_rap_app_t* app) +{ + if (app->handle) + { + dlclose (app->handle); + app->handle = NULL; + } + + if (!rtems_chain_is_node_off_chain (&app->node)) + rtems_chain_extract (&app->node); +} + +static bool +rtems_rap_match_name (rtems_rap_app_t* app, const char* name) +{ + const char* a; + + /* + * Assume the app name is absolute, ie points to the file on disk. This means + * there is at least one delimiter in the name. + */ + + if (strncmp (app->name, name, strlen (name)) == 0) + return true; + + a = app->name + strlen (app->name) - 1; + + while (a >= app->name) + { + if (rtems_filesystem_is_delimiter (*a)) + { + const char* n = name; + + ++a; + + while (*a && *n) + { + if (*a == '.') + { + if (*n == '\0') + return true; + } + + ++a; + ++n; + } + + return false; + } + + --a; + } + + return false; +} + +static void +rtems_rap_get_rtl_error (void) +{ + rap_.last_errno = + rtems_rtl_get_error (rap_.last_error, sizeof (rap_.last_error)); +} + +static void +rtems_rap_set_error (int error, const char* format, ...) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + va_list ap; + va_start (ap, format); + rap->last_errno = error; + vsnprintf (rap->last_error, sizeof (rap->last_error), format, ap); + rtems_rap_unlock (); + va_end (ap); +} + +bool +rtems_rap_load (const char* name, int mode, int argc, const char* argv[]) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + + if (!rap) + return false; + + if (rap_verbose) + printf ("rap: loading '%s'\n", name); + + /* + * See if the app has already been loaded. + */ + if (!rtems_rap_find (name)) + { + rtems_rap_app_t* app; + rtems_rap_entry_t init; + rtems_rap_entry_t fini; + size_t size = 0; + int r; + + /* + * Allocate a new application descriptor and attempt to load it. + */ + app = rtems_rap_app_alloc (); + if (app == NULL) + { + rtems_rap_set_error (ENOMEM, "no memory for application"); + rtems_rap_unlock (); + return false; + } + + /* + * Find the file in the file system using the search path. + */ + if (!rtems_rtl_find_file (name, getenv ("PATH"), &app->name, &size)) + { + rtems_rap_set_error (ENOENT, "file not found"); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + + app->handle = dlopen (app->name, RTLD_NOW | mode); + if (!app->handle) + { + rtems_rap_get_rtl_error (); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + + init = dlsym (app->handle, RTL_ENTRY_POINT); + if (!init) + { + rtems_rap_get_rtl_error (); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + + fini = dlsym (app->handle, RTL_ENTRY_POINT); + if (!fini) + { + rtems_rap_get_rtl_error (); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + + r = init (argc, argv); + if (r != 0) + { + rtems_rap_set_error (r, "init call failure"); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + } + + rtems_rap_unlock (); + + return true; +} + +bool +rtems_rap_unload (const char* name) +{ + rtems_rap_app_t* app; + rtems_rap_entry_t fini; + int r; + + rtems_rap_lock (); + + app = rtems_rap_find (name); + + if (rap_verbose) + printf ("rap: unloading '%s'\n", name); + + if (!app) + { + rtems_rap_set_error (ENOENT, "invalid handle"); + rtems_rap_unlock (); + return false; + } + + fini = dlsym (app->handle, RTL_ENTRY_POINT); + if (!fini) + { + rtems_rap_get_rtl_error (); + rtems_rap_unlock (); + return false; + } + + r = fini (0, NULL); + if (r != 0) + { + rtems_rap_set_error (r, "fini failure"); + rtems_rap_unlock (); + return false; + } + + rtems_rap_app_free (app); + rtems_rap_unlock (); + + return true; +} + +void* +rtems_rap_find (const char* name) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + rtems_chain_node* node; + + node = rtems_chain_first (&rap->apps); + + while (!rtems_chain_is_tail (&rap->apps, node)) + { + rtems_rap_app_t* app = (rtems_rap_app_t*) node; + if (rtems_rap_match_name (app, name)) + { + rtems_rap_unlock (); + return app; + } + node = rtems_chain_next (node); + } + + rtems_rap_unlock (); + + return NULL; +} + +bool +rtems_rap_iterate (rtems_rap_iterator_t iterator) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + rtems_chain_node* node; + bool result = true; + + node = rtems_chain_first (&rap->apps); + + while (!rtems_chain_is_tail (&rap->apps, node)) + { + rtems_rap_app_t* app = (rtems_rap_app_t*) node; + result = iterator (app); + if (!result) + break; + node = rtems_chain_next (node); + } + + rtems_rap_unlock (); + + return result; +} + +const char* +rtems_rap_name (void* handle) +{ + rtems_rap_app_t* app = rtems_rap_check_handle (handle); + if (app) + return app->name; + return NULL; +} + +void* +rtems_rap_dl_handle (void* handle) +{ + rtems_rap_app_t* app = rtems_rap_check_handle (handle); + if (app) + return app->handle; + return NULL; +} + +int +rtems_rap_get_error (char* message, size_t max_message) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + int last_errno = rap->last_errno; + strncpy (message, rap->last_error, sizeof (rap->last_error)); + rtems_rap_unlock (); + return last_errno; +} diff --git a/cpukit/libdl/rap.h b/cpukit/libdl/rap.h new file mode 100644 index 0000000000..e53699f93f --- /dev/null +++ b/cpukit/libdl/rap.h @@ -0,0 +1,115 @@ +/* + * COPYRIGHT (c) 2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rap + * + * @brief RTEMS Application Loader + * + * This is the RTEMS Application loader for files in the RAP format. + */ + +#if !defined (_RAP_H_) +#define _RAP_H_ + +#include <rtems.h> +#include <rtems/chain.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup rtems_rap RTEMS Application Loader + * + * The module implements an application loader for files in the RAP format. The + * RAP format is: + * + * <header> + * <compressed container> + * + * The compressed container is a stream of ELF relocatable object files. + * + * TBD. + */ + +/** + * The module iterator handle. + */ +typedef bool (*rtems_rap_iterator_t) (void* handle); + +/** + * Load an application. + * + * @param name The name of the application file. + * @return bool True if the module loads else an error. + */ +bool rtems_rap_load (const char* name, int mode, int argc, const char* argv[]); + +/** + * Unload an application. + * + * @param obj The application descriptor. + * @retval true The application file has been unloaded. + * @retval false The application could not be unloaded. + */ +bool rtems_rap_unload (const char* name); + +/** + * Find the application handle given a file name. + * + * @param name The name of the application file. It can be absolute or + * relative. Relative names can the basename with an extension. + * @retval NULL No application file with that name found. + * @return void* The application descriptor. + */ +void* rtems_rap_find (const char* name); + +/** + * Run an iterator over the modules calling the iterator function. + * + * @param iterator The iterator function. + * @retval true The iterator function returned did not return false. + * @retval false The iterator function returned false.. + */ +bool rtems_rap_iterate (rtems_rap_iterator_t iterator); + +/** + * Return the name of the module given a handle. + * + * @param handle The module handle. + * @return const char* The name of the module if the handle is valid else it + * is NULL. + */ +const char* rtems_rap_name (void* handle); + +/** + * Return the DL handle used to load the module given the RAP handle. + * + * @param handle The module handle. + * @return void* The DL handle returned by the dlopen call. + */ +void* rtems_rap_dl_handle (void* handle); + +/** + * Get the last error message clearing it. This call is not thread safe is + * multiple threads are loading object files at the same time. This call + * follows the model provided by the dlopen family of calls. + * + * @param message Pointer to a buffer to copy the message into. + * @param max_message The maximum message that can be copied. + * @return int The last error number. + */ +int rtems_rap_get_error (char* message, size_t max_message); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-alloc-heap.c b/cpukit/libdl/rtl-alloc-heap.c new file mode 100644 index 0000000000..44a4816c5d --- /dev/null +++ b/cpukit/libdl/rtl-alloc-heap.c @@ -0,0 +1,33 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Allocator for the standard heap. + */ + +#include <stdlib.h> + +#include "rtl-alloc-heap.h" + +void +rtems_rtl_alloc_heap (bool allocate, + rtems_rtl_alloc_tag_t tag, + void** address, + size_t size) +{ + if (allocate) + *address = malloc (size); + else + { + free (*address); + *address = NULL; + } +} diff --git a/cpukit/libdl/rtl-alloc-heap.h b/cpukit/libdl/rtl-alloc-heap.h new file mode 100644 index 0000000000..d9276553e4 --- /dev/null +++ b/cpukit/libdl/rtl-alloc-heap.h @@ -0,0 +1,47 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Allocator for the standard heap. + */ + +#if !defined (_RTEMS_RTL_ALLOC_HEAP_H_) +#define _RTEMS_RTL_ALLOC_HEAP_H_ + +#include <rtems/rtl/rtl-allocator.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Allocator handler for the standard libc heap. + * + * @param allocation If true the request is to allocate memory else free. + * @param tag The type of allocation request. + * @param address Pointer to the memory address. If an allocation the value is + * unspecific on entry and the allocated address or NULL on + * exit. The NULL value means the allocation failed. If a delete + * or free request the memory address is the block to free. A + * free request of NULL is silently ignored. + * @param size The size of the allocation if an allocation request and + * not used if deleting or freeing a previous allocation. + */ +void rtems_rtl_alloc_heap(bool allocate, + rtems_rtl_alloc_tag_t tag, + void** address, + size_t size); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-allocator.c b/cpukit/libdl/rtl-allocator.c new file mode 100644 index 0000000000..b845013fd8 --- /dev/null +++ b/cpukit/libdl/rtl-allocator.c @@ -0,0 +1,210 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Allocator + */ + +#include <stdio.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-alloc-heap.h" +#include "rtl-trace.h" + +/** + * Tags as symbols for tracing. + */ +#if RTEMS_RTL_TRACE +static const char* tag_labels[6] = +{ + "OBJECT", + "SYMBOL", + "EXTERNAL", + "READ", + "READ_WRITE", + "READ_EXEC", +}; +#define rtems_rtl_trace_tag_label(_l) tag_labels[_l] +#else +#define rtems_rtl_trace_tag_label(_l) "" +#endif + +void +rtems_rtl_alloc_initialise (rtems_rtl_alloc_data_t* data) +{ + int c; + data->allocator = rtems_rtl_alloc_heap; + for (c = 0; c < RTEMS_RTL_ALLOC_TAGS; ++c) + rtems_chain_initialize_empty (&data->indirects[c]); +} + +void* +rtems_rtl_alloc_new (rtems_rtl_alloc_tag_t tag, size_t size, bool zero) +{ + rtems_rtl_data_t* rtl = rtems_rtl_lock (); + void* address = NULL; + + if (rtl) + rtl->allocator.allocator (true, tag, &address, size); + + rtems_rtl_unlock (); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR)) + printf ("rtl: alloc: new: %s addr=%p size=%zu\n", + rtems_rtl_trace_tag_label (tag), address, size); + + if (zero) + memset (address, 0, size); + + return address; +} + +void +rtems_rtl_alloc_del (rtems_rtl_alloc_tag_t tag, void* address) +{ + rtems_rtl_data_t* rtl = rtems_rtl_lock (); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR)) + printf ("rtl: alloc: del: %s addr=%p\n", + rtems_rtl_trace_tag_label (tag), address); + + if (rtl && address) + rtl->allocator.allocator (false, tag, &address, 0); + + rtems_rtl_unlock (); +} + +rtems_rtl_allocator_t +rtems_rtl_alloc_hook (rtems_rtl_allocator_t handler) +{ + rtems_rtl_data_t* rtl = rtems_rtl_lock (); + rtems_rtl_allocator_t previous = rtl->allocator.allocator; + rtl->allocator.allocator = handler; + rtems_rtl_unlock (); + return previous; +} + +void +rtems_rtl_alloc_indirect_new (rtems_rtl_alloc_tag_t tag, + rtems_rtl_ptr_t* handle, + size_t size) +{ + rtems_rtl_data_t* rtl = rtems_rtl_lock (); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR)) + { + if (!rtems_rtl_ptr_null (handle)) + printf ("rtl: alloc: inew: %s handle=%p: not null\n", + rtems_rtl_trace_tag_label (tag), handle); + printf ("rtl: alloc: inew: %s handle=%p size=%zd\n", + rtems_rtl_trace_tag_label (tag), handle, size); + } + + if (rtl) + { + rtems_rtl_alloc_data_t* allocator = &rtl->allocator; + handle->pointer = rtems_rtl_alloc_new (tag, size, false); + if (!rtems_rtl_ptr_null (handle)) + rtems_chain_append_unprotected (&allocator->indirects[tag], + &handle->node); + } + + rtems_rtl_unlock (); +} + +void +rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag, + rtems_rtl_ptr_t* handle) +{ + rtems_rtl_data_t* rtl = rtems_rtl_lock (); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR)) + { + if (rtems_rtl_ptr_null (handle)) + printf ("rtl: alloc: idel: %s handle=%p: is null\n", + rtems_rtl_trace_tag_label (tag), handle); + printf ("rtl: alloc: idel: %s handle=%p\n", + rtems_rtl_trace_tag_label (tag), handle); + } + + if (rtl && !rtems_rtl_ptr_null (handle)) + { + rtems_chain_extract_unprotected (&handle->node); + rtems_rtl_alloc_del (tag, &handle->pointer); + } +} + +bool +rtems_rtl_alloc_module_new (void** text_base, size_t text_size, + void** const_base, size_t const_size, + void** data_base, size_t data_size, + void** bss_base, size_t bss_size) +{ + *text_base = *const_base = *data_base = *bss_base = NULL; + + if (text_size) + { + *text_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ_EXEC, + text_size, false); + if (!*text_base) + { + return false; + } + } + + if (const_size) + { + *const_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ, + const_size, false); + if (!*const_base) + { + rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base); + return false; + } + } + + if (data_size) + { + *data_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ_WRITE, + data_size, false); + if (!*data_base) + { + rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base); + return false; + } + } + + if (bss_size) + { + *bss_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ_WRITE, + bss_size, false); + if (!*bss_base) + { + rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base); + return false; + } + } + + return true; +} + +void +rtems_rtl_alloc_module_del (void** text_base, + void** const_base, + void** data_base, + void** bss_base) +{ + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *bss_base); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *data_base); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *const_base); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_EXEC, *text_base); + *text_base = *const_base = *data_base = *bss_base = NULL; +} diff --git a/cpukit/libdl/rtl-allocator.h b/cpukit/libdl/rtl-allocator.h new file mode 100644 index 0000000000..8e90b7b81c --- /dev/null +++ b/cpukit/libdl/rtl-allocator.h @@ -0,0 +1,176 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Allocator + */ + +#if !defined (_RTEMS_RTL_ALLOCATOR_H_) +#define _RTEMS_RTL_ALLOCATOR_H_ + +#include <stdbool.h> + +#include "rtl-indirect-ptr.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Define the types of allocation the loader requires. + * + * @note It is best to use the object tag for general memory allocation and to + * leave the tags with specific access properties to the module data + */ +enum rtems_rtl_alloc_tags_e { + RTEMS_RTL_ALLOC_OBJECT, /**< A generic memory object. */ + RTEMS_RTL_ALLOC_SYMBOL, /**< Memory used for symbols. */ + RTEMS_RTL_ALLOC_EXTERNAL, /**< Memory used for external symbols. */ + RTEMS_RTL_ALLOC_READ, /**< The memory is read only. */ + RTEMS_RTL_ALLOC_READ_WRITE, /**< The memory is read and write. */ + RTEMS_RTL_ALLOC_READ_EXEC /**< The memory is read and executable. */ +}; + +/** + * The allocator tag type. + */ +typedef enum rtems_rtl_alloc_tags_e rtems_rtl_alloc_tag_t; + +/** + * The number of tags. + */ +#define RTEMS_RTL_ALLOC_TAGS ((size_t) (RTEMS_RTL_ALLOC_READ_EXEC + 1)) + +/** + * Allocator handler handles all RTL allocations. It can be hooked and + * overridded for customised allocation schemes or memory maps. + * + * @param allocation If true the request is to allocate memory else free. + * @param tag The type of allocation request. + * @param address Pointer to the memory address. If an allocation the value is + * unspecific on entry and the allocated address or NULL on + * exit. The NULL value means the allocation failed. If a delete + * or free request the memory address is the block to free. A + * free request of NULL is silently ignored. + * @param size The size of the allocation if an allocation request and + * not used if deleting or freeing a previous allocation. + */ +typedef void (*rtems_rtl_allocator_t)(bool allocate, + rtems_rtl_alloc_tag_t tag, + void** address, + size_t size); + +/** + * The allocator data. + */ +struct rtems_rtl_alloc_data_s { + /**< The memory allocator handler. */ + rtems_rtl_allocator_t allocator; + /**< The indirect pointer chains. */ + rtems_chain_control indirects[RTEMS_RTL_ALLOC_TAGS]; +}; + +typedef struct rtems_rtl_alloc_data_s rtems_rtl_alloc_data_t; + +/** + * Initialise the allocate data. + * + * @param data The data to initialise. + */ +void rtems_rtl_alloc_initialise (rtems_rtl_alloc_data_t* data); + +/** + * The Runtime Loader allocator new allocates new memory and optionally clear + * the memory if requested. + * + * @param tag The type of allocation request. + * @param size The size of the allocation. + * @param zero If true the memory is cleared. + * @return void* The memory address or NULL is not memory available. + */ +void* rtems_rtl_alloc_new (rtems_rtl_alloc_tag_t tag, size_t size, bool zero); + +/** + * The Runtime Loader allocator delete deletes allocated memory. + * + * @param tag The type of allocation request. + * @param address The memory address to delete. A NULL is ignored. + */ +void rtems_rtl_alloc_del (rtems_rtl_alloc_tag_t tag, void* address); + +/** + * Hook the Runtime Loader allocatior. A handler can call the previous handler + * in the chain to use it for specific tags. The default handler uses the + * system heap. Do not unhook your handler if memory it allocates has not been + * returned. + * + * @param handler The handler to use as the allocator. + * @return rtems_rtl_alloc_handler_t The previous handler. + */ +rtems_rtl_allocator_t rtems_rtl_alloc_hook (rtems_rtl_allocator_t handler); + +/** + * Allocate memory to an indirect handle. + * + * @param tag The type of allocation request. + * @param handle The handle to allocate the memory to. + * @param size The size of the allocation. + */ +void rtems_rtl_alloc_indirect_new (rtems_rtl_alloc_tag_t tag, + rtems_rtl_ptr_t* handle, + size_t size); + +/** + * Free memory from an indirect handle. + * + * @param tag The type of allocation request. + * @param handle The handle to free the memory from. + */ +void rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag, + rtems_rtl_ptr_t* handle); + +/** + * Allocate the memory for a module given the size of the text, const, data and + * bss sections. If any part of the allocation fails the no memory is + * allocated. + * + * @param text_base Pointer to the text base pointer. + * @param text_size The size of the read/exec section. + * @param const_base Pointer to the const base pointer. + * @param const_size The size of the read only section. + * @param data_base Pointer to the data base pointer. + * @prarm data_size The size of the read/write secton. + * @param bss_base Pointer to the bss base pointer. + * @param bss_size The size of the read/write. + * @retval true The memory has been allocated. + * @retval false The allocation of memory has failed. + */ +bool rtems_rtl_alloc_module_new (void** text_base, size_t text_size, + void** const_base, size_t const_size, + void** data_base, size_t data_size, + void** bss_base, size_t bss_size); + +/** + * Free the memory allocated to a module. + * + * @param text_base Pointer to the text base pointer. + * @param const_base Pointer to the const base pointer. + * @param data_base Pointer to the data base pointer. + * @param bss_base Pointer to the bss base pointer. + */ +void rtems_rtl_alloc_module_del (void** text_base, void** const_base, + void** data_base, void** bss_base); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-chain-iterator.c b/cpukit/libdl/rtl-chain-iterator.c new file mode 100644 index 0000000000..39184ee513 --- /dev/null +++ b/cpukit/libdl/rtl-chain-iterator.c @@ -0,0 +1,57 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor Chain Iterator + * + * A means of executing an iterator on a chain. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rtl-chain-iterator.h" + +bool +rtems_rtl_chain_iterate (rtems_chain_control* chain, + rtems_chain_iterator iterator, + void* data) +{ + rtems_chain_node* node = rtems_chain_first (chain); + while (!rtems_chain_is_tail (chain, node)) + { + rtems_chain_node* next_node = rtems_chain_next (node); + if (!iterator (node, data)) + return false; + node = next_node; + } + return true; +} + +/** + * Count iterator. + */ +static bool +rtems_rtl_count_iterator (rtems_chain_node* node, void* data) +{ + int* count = data; + ++(*count); + return true; +} + +int +rtems_rtl_chain_count (rtems_chain_control* chain) +{ + int count = 0; + rtems_rtl_chain_iterate (chain, rtems_rtl_count_iterator, &count); + return count; +} diff --git a/cpukit/libdl/rtl-chain-iterator.h b/cpukit/libdl/rtl-chain-iterator.h new file mode 100644 index 0000000000..b3781e07e9 --- /dev/null +++ b/cpukit/libdl/rtl-chain-iterator.h @@ -0,0 +1,59 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Chain Iterator. + */ + +#if !defined (_RTEMS_RTL_CHAIN_ITERATOR_H_) +#define _RTEMS_RTL_CHAIN_ITERATOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <rtems/chain.h> + +/** + * Chain iterator handler. + */ +typedef bool (*rtems_chain_iterator) (rtems_chain_node* node, void* data); + +/** + * Iterate a chain of nodes invoking the iterator handler. Supply a data + * pointer the iterator moves data between the invoker and the iterator. + * + * The iterator allows removal of the node from the chain. + * + * @param chain The chain of nodes to iterator over. + * @param iterator The iterator handler called once for each node. + * @param data Pointer to the data used by the iterator. + * @retval true The whole chain was iterated over. + * @retval false The iterator returned false. + */ +bool +rtems_rtl_chain_iterate (rtems_chain_control* chain, + rtems_chain_iterator iterator, + void* data); + +/** + * Count the number of nodes on the chain. + * + * @param chain The chain to count the nodes of. + * @return int The number of nodes. + */ +int rtems_rtl_chain_count (rtems_chain_control* chain); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-debugger.c b/cpukit/libdl/rtl-debugger.c new file mode 100644 index 0000000000..2eff2bd055 --- /dev/null +++ b/cpukit/libdl/rtl-debugger.c @@ -0,0 +1,96 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtl + * + * @brief RTEMS Module Loading Debugger Interface. + * + * Inspection of run-time linkers in NetBSD and Android show a common type of + * structure that is used to interface to GDB. The NetBSD definition of this + * interface is being used and is defined in <link.h>. It defines a protocol + * that is used by GDB to inspect the state of dynamic libraries. I have not + * checked GDB code at when writing this comment but I suspect GDB sets a break + * point on the r_brk field of _rtld_debug and it has code that detects this + * break point being hit. When this happens it reads the state and performs the + * operation based on the r_state field. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <link.h> +#include <rtems/rtl/rtl.h> +#include "rtl-trace.h" +#include "rtl-obj-fwd.h" + +struct r_debug _rtld_debug; + +void +_rtld_debug_state (void) +{ + /* + * Empty. GDB only needs to hit this location. + */ +} + +int +_rtld_linkmap_add (rtems_rtl_obj_t* obj) +{ + struct link_map* l = (struct link_map*)obj->detail; + struct link_map* prev; + uint32_t obj_num = obj->obj_num; + int i; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + printf ("rtl: linkmap_add\n"); + + for (i = 0; i < obj_num; ++i) + { + l[i].sec_addr[rap_text] = obj->text_base; + l[i].sec_addr[rap_const] = obj->const_base; + l[i].sec_addr[rap_data] = obj->data_base; + l[i].sec_addr[rap_bss] = obj->bss_base; + } + + if (_rtld_debug.r_map == NULL) + { + _rtld_debug.r_map = l; + return true; + } + + for (prev = _rtld_debug.r_map; prev->l_next != NULL; prev = prev->l_next); + + l->l_prev = prev; + prev->l_next = l; + + return true; +} + +void +_rtld_linkmap_delete (rtems_rtl_obj_t* obj) +{ + struct link_map* l = (struct link_map*)obj->detail; + /* link_maps are allocated together if not 1 */ + struct link_map* e = l + obj->obj_num - 1; + + while (e && e->l_next) e = e->l_next; + + if (l->l_prev == NULL) + { + if ((_rtld_debug.r_map = e->l_next) != NULL) + e->l_next->l_prev = NULL; + return; + } + if ((l->l_prev->l_next = e->l_next) != NULL) + e->l_next->l_prev = l->l_prev; + return; +} diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c new file mode 100644 index 0000000000..e4f1ffc007 --- /dev/null +++ b/cpukit/libdl/rtl-elf.c @@ -0,0 +1,882 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor + * + * This is the RTL implementation. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" +#include "rtl-unresolved.h" + +/** + * The offsets in the unresolved array. + */ +#define REL_R_OFFSET (0) +#define REL_R_INFO (1) +#define REL_R_ADDEND (2) + +/** + * The ELF format signature. + */ +static rtems_rtl_loader_format_t elf_sig = +{ + .label = "ELF", + .flags = RTEMS_RTL_FMT_ELF +}; + +static bool +rtems_rtl_elf_machine_check (Elf_Ehdr* ehdr) +{ + /* + * This code is determined by the NetBSD machine headers. + */ + switch (ehdr->e_machine) + { + ELFDEFNNAME (MACHDEP_ID_CASES) + default: + return false; + } + return true; +} + +bool +rtems_rtl_elf_find_symbol (rtems_rtl_obj_t* obj, + const Elf_Sym* sym, + const char* symname, + Elf_Word* value) +{ + rtems_rtl_obj_sect_t* sect; + + if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE) + { + rtems_rtl_obj_sym_t* symbol = rtems_rtl_symbol_global_find (symname); + if (!symbol) + { + rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname); + return false; + } + + *value = (Elf_Word) symbol->value; + return true; + } + + sect = rtems_rtl_obj_find_section_by_index (obj, sym->st_shndx); + if (!sect) + { + rtems_rtl_set_error (EINVAL, "reloc symbol's section not found"); + return false; + } + + *value = sym->st_value + (Elf_Word) sect->base; + return true; +} + +static bool +rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_t* sect, + void* data) +{ + rtems_rtl_obj_cache_t* symbols; + rtems_rtl_obj_cache_t* strings; + rtems_rtl_obj_cache_t* relocs; + rtems_rtl_obj_sect_t* targetsect; + rtems_rtl_obj_sect_t* symsect; + rtems_rtl_obj_sect_t* strtab; + bool is_rela; + size_t reloc_size; + int reloc; + + /* + * First check if the section the relocations are for exists. If it does not + * exist ignore these relocations. They are most probably debug sections. + */ + targetsect = rtems_rtl_obj_find_section_by_index (obj, sect->info); + if (!targetsect) + return true; + + rtems_rtl_obj_caches (&symbols, &strings, &relocs); + + if (!symbols || !strings || !relocs) + return false; + + symsect = rtems_rtl_obj_find_section (obj, ".symtab"); + if (!symsect) + { + rtems_rtl_set_error (EINVAL, "no .symtab section"); + return false; + } + + strtab = rtems_rtl_obj_find_section (obj, ".strtab"); + if (!strtab) + { + rtems_rtl_set_error (EINVAL, "no .strtab section"); + return false; + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: relocation: %s, syms:%s\n", sect->name, symsect->name); + + /* + * Handle the different relocation record types. + */ + is_rela = ((sect->flags & RTEMS_RTL_OBJ_SECT_RELA) == + RTEMS_RTL_OBJ_SECT_RELA) ? true : false; + reloc_size = is_rela ? sizeof (Elf_Rela) : sizeof (Elf_Rel); + + for (reloc = 0; reloc < (sect->size / reloc_size); ++reloc) + { + uint8_t relbuf[reloc_size]; + const Elf_Rela* rela = (const Elf_Rela*) relbuf; + const Elf_Rel* rel = (const Elf_Rel*) relbuf; + Elf_Sym sym; + const char* symname = NULL; + off_t off; + Elf_Word type; + Elf_Word symvalue = 0; + bool relocate; + + off = obj->ooffset + sect->offset + (reloc * reloc_size); + + if (!rtems_rtl_obj_cache_read_byval (relocs, fd, off, + &relbuf[0], reloc_size)) + return false; + + if (is_rela) + off = (obj->ooffset + symsect->offset + + (ELF_R_SYM (rela->r_info) * sizeof (sym))); + else + off = (obj->ooffset + symsect->offset + + (ELF_R_SYM (rel->r_info) * sizeof (sym))); + + if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off, + &sym, sizeof (sym))) + return false; + + /* + * Only need the name of the symbol if global. + */ + if (ELF_ST_TYPE (sym.st_info) == STT_NOTYPE) + { + size_t len; + off = obj->ooffset + strtab->offset + sym.st_name; + len = RTEMS_RTL_ELF_STRING_MAX; + + if (!rtems_rtl_obj_cache_read (strings, fd, off, + (void**) &symname, &len)) + return false; + } + + /* + * See if the record references an external symbol. If it does find the + * symbol value. If the symbol cannot be found flag the object file as + * having unresolved externals and store the externals. The load of an + * object after this one may provide the unresolved externals. + */ + if (is_rela) + type = ELF_R_TYPE(rela->r_info); + else + type = ELF_R_TYPE(rel->r_info); + + relocate = true; + + if (rtems_rtl_elf_rel_resolve_sym (type)) + { + if (!rtems_rtl_elf_find_symbol (obj, &sym, symname, &symvalue)) + { + uint16_t flags = 0; + rtems_rtl_word_t rel_words[3]; + + relocate = false; + + if (is_rela) + { + flags = 1; + rel_words[REL_R_OFFSET] = rela->r_offset; + rel_words[REL_R_INFO] = rela->r_info; + rel_words[REL_R_ADDEND] = rela->r_addend; + } + else + { + rel_words[REL_R_OFFSET] = rel->r_offset; + rel_words[REL_R_INFO] = rel->r_info; + rel_words[REL_R_ADDEND] = 0; + } + + if (!rtems_rtl_unresolved_add (obj, + flags, + symname, + targetsect->section, + rel_words)) + return false; + + ++obj->unresolved; + } + } + + if (relocate) + { + if (is_rela) + { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rela: sym:%s(%-2d)=%08lx type:%-2d off:%08lx addend:%d\n", + symname, (int) ELF_R_SYM (rela->r_info), symvalue, + (int) ELF_R_TYPE (rela->r_info), rela->r_offset, (int) rela->r_addend); + if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect, + symname, sym.st_info, symvalue)) + return false; + } + else + { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rel: sym:%s(%-2d)=%08lx type:%-2d off:%08lx\n", + symname, (int) ELF_R_SYM (rel->r_info), symvalue, + (int) ELF_R_TYPE (rel->r_info), rel->r_offset); + if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect, + symname, sym.st_info, symvalue)) + return false; + } + } + } + + /* + * Set the unresolved externals status if there are unresolved externals. + */ + if (obj->unresolved) + obj->flags |= RTEMS_RTL_OBJ_UNRESOLVED; + + return true; +} + +bool +rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc_t* reloc, + rtems_rtl_obj_sym_t* sym) +{ + rtems_rtl_obj_sect_t* sect; + bool is_rela; + Elf_Word symvalue; + + is_rela =reloc->flags & 1; + + sect = rtems_rtl_obj_find_section_by_index (reloc->obj, reloc->sect); + if (!sect) + { + rtems_rtl_set_error (ENOEXEC, "unresolved sect not found"); + return false; + } + + symvalue = (Elf_Word) (intptr_t) sym->value; + if (is_rela) + { + Elf_Rela rela; + rela.r_offset = reloc->rel[REL_R_OFFSET]; + rela.r_info = reloc->rel[REL_R_INFO]; + rela.r_addend = reloc->rel[REL_R_ADDEND]; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rela: sym:%-2d type:%-2d off:%08lx addend:%d\n", + (int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info), + rela.r_offset, (int) rela.r_addend); + if (!rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect, + sym->name, sym->data, symvalue)) + return false; + } + else + { + Elf_Rel rel; + rel.r_offset = reloc->rel[REL_R_OFFSET]; + rel.r_info = reloc->rel[REL_R_INFO]; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rel: sym:%-2d type:%-2d off:%08lx\n", + (int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info), + rel.r_offset); + if (!rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect, + sym->name, sym->data, symvalue)) + return false; + } + + if (reloc->obj->unresolved) + { + --reloc->obj->unresolved; + if (!reloc->obj->unresolved) + reloc->obj->flags &= ~RTEMS_RTL_OBJ_UNRESOLVED; + } + + return true; +} + +static bool +rtems_rtl_elf_symbols (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_t* sect, + void* data) +{ + rtems_rtl_obj_cache_t* symbols; + rtems_rtl_obj_cache_t* strings; + rtems_rtl_obj_sect_t* strtab; + int globals; + int string_space; + char* string; + int sym; + + strtab = rtems_rtl_obj_find_section (obj, ".strtab"); + if (!strtab) + { + rtems_rtl_set_error (EINVAL, "no .strtab section"); + return false; + } + + rtems_rtl_obj_caches (&symbols, &strings, NULL); + + if (!symbols || !strings) + return false; + + /* + * Find the number of globals and the amount of string space + * needed. Also check for duplicate symbols. + */ + + globals = 0; + string_space = 0; + + for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym) + { + Elf_Sym symbol; + off_t off; + const char* name; + size_t len; + + off = obj->ooffset + sect->offset + (sym * sizeof (symbol)); + + if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off, + &symbol, sizeof (symbol))) + return false; + + off = obj->ooffset + strtab->offset + symbol.st_name; + len = RTEMS_RTL_ELF_STRING_MAX; + + if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len)) + return false; + + /* + * Only keep the functions and global or weak symbols. + */ + if ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) || + (ELF_ST_TYPE (symbol.st_info) == STT_FUNC)) + { + if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || + (ELF_ST_BIND (symbol.st_info) == STB_WEAK)) + { + /* + * If there is a globally exported symbol already present and this + * symbol is not weak raise an error. If the symbol is weak and present + * globally ignore this symbol and use the global one and if it is not + * present take this symbol global or weak. We accept the first weak + * symbol we find and make it globally exported. + */ + if (rtems_rtl_symbol_global_find (name) && + (ELF_ST_BIND (symbol.st_info) != STB_WEAK)) + { + rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name); + return false; + } + else + { + ++globals; + string_space += strlen (name) + 1; + } + } + } + } + + if (globals) + { + rtems_rtl_obj_sym_t* gsym; + + obj->global_size = globals * sizeof (rtems_rtl_obj_sym_t) + string_space; + obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, + obj->global_size, true); + if (!obj->global_table) + { + obj->global_size = 0; + rtems_rtl_set_error (ENOMEM, "no memory for obj global syms"); + return false; + } + + obj->global_syms = globals; + + for (sym = 0, + gsym = obj->global_table, + string = (((char*) obj->global_table) + + (globals * sizeof (rtems_rtl_obj_sym_t))); + sym < (sect->size / sizeof (Elf_Sym)); + ++sym) + { + Elf_Sym symbol; + off_t off; + const char* name; + size_t len; + + off = obj->ooffset + sect->offset + (sym * sizeof (symbol)); + + if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off, + &symbol, sizeof (symbol))) + { + free (obj->global_table); + obj->global_table = NULL; + obj->global_syms = 0; + obj->global_size = 0; + return false; + } + + off = obj->ooffset + strtab->offset + symbol.st_name; + len = RTEMS_RTL_ELF_STRING_MAX; + + if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len)) + return false; + + if (((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) || + (ELF_ST_TYPE (symbol.st_info) == STT_FUNC)) && + ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || + (ELF_ST_BIND (symbol.st_info) == STB_WEAK))) + { + rtems_rtl_obj_sect_t* symsect; + symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx); + if (!symsect) + { + free (obj->global_table); + obj->global_table = NULL; + obj->global_syms = 0; + obj->global_size = 0; + rtems_rtl_set_error (EINVAL, "sym section not found"); + return false; + } + + rtems_chain_set_off_chain (&gsym->node); + + memcpy (string, name, strlen (name) + 1); + gsym->name = string; + string += strlen (name) + 1; + gsym->value = symbol.st_value + (uint8_t*) symsect->base; + gsym->data = symbol.st_info; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) + printf ("rtl: sym:add:%-2d name:%-2d:%-20s bind:%-2d type:%-2d val:%8p sect:%d size:%d\n", + sym, (int) symbol.st_name, gsym->name, + (int) ELF_ST_BIND (symbol.st_info), + (int) ELF_ST_TYPE (symbol.st_info), + gsym->value, symbol.st_shndx, + (int) symbol.st_size); + + ++gsym; + } + } + + rtems_rtl_symbol_obj_add (obj); + } + + return true; +} + +static bool +rtems_rtl_elf_loader (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_t* sect, + void* data) +{ + uint8_t* base_offset; + size_t len; + + if (lseek (fd, obj->ooffset + sect->offset, SEEK_SET) < 0) + { + rtems_rtl_set_error (errno, "section load seek failed"); + return false; + } + + base_offset = sect->base; + len = sect->size; + + while (len) + { + ssize_t r = read (fd, base_offset, len); + if (r <= 0) + { + rtems_rtl_set_error (errno, "section load read failed"); + return false; + } + base_offset += r; + len -= r; + } + + return true; +} + +static bool +rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr) +{ + rtems_rtl_obj_cache_t* sects; + rtems_rtl_obj_cache_t* strings; + int section; + off_t sectstroff; + off_t off; + Elf_Shdr shdr; + + rtems_rtl_obj_caches (§s, &strings, NULL); + + if (!sects || !strings) + return false; + + /* + * Get the offset to the section string table. + */ + off = obj->ooffset + ehdr->e_shoff + (ehdr->e_shstrndx * ehdr->e_shentsize); + + if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr))) + return false; + + if (shdr.sh_type != SHT_STRTAB) + { + rtems_rtl_set_error (EINVAL, "bad .sectstr section type"); + return false; + } + + sectstroff = obj->ooffset + shdr.sh_offset; + + for (section = 0; section < ehdr->e_shnum; ++section) + { + uint32_t flags; + + off = obj->ooffset + ehdr->e_shoff + (section * ehdr->e_shentsize); + + if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr))) + return false; + + flags = 0; + + switch (shdr.sh_type) + { + case SHT_NULL: + /* + * Ignore. + */ + break; + + case SHT_PROGBITS: + /* + * There are 2 program bits sections. One is the program text and the + * other is the program data. The program text is flagged + * alloc/executable and the program data is flagged alloc/writable. + */ + if ((shdr.sh_flags & SHF_ALLOC) == SHF_ALLOC) + { + if ((shdr.sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR) + flags = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD; + else if ((shdr.sh_flags & SHF_WRITE) == SHF_WRITE) + flags = RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD; + else + flags = RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD; + } + break; + + case SHT_NOBITS: + /* + * There is 1 NOBIT section which is the .bss section. There is nothing + * but a definition as the .bss is just a clear region of memory. + */ + if ((shdr.sh_flags & (SHF_ALLOC | SHF_WRITE)) == (SHF_ALLOC | SHF_WRITE)) + flags = RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO; + break; + + case SHT_RELA: + flags = RTEMS_RTL_OBJ_SECT_RELA; + break; + + case SHT_REL: + /* + * The sh_link holds the section index for the symbol table. The sh_info + * holds the section index the relocations apply to. + */ + flags = RTEMS_RTL_OBJ_SECT_REL; + break; + + case SHT_SYMTAB: + flags = RTEMS_RTL_OBJ_SECT_SYM; + break; + + case SHT_STRTAB: + flags = RTEMS_RTL_OBJ_SECT_STR; + break; + + default: + printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n", + section, (int) shdr.sh_type, (int) shdr.sh_flags); + break; + } + + if (flags != 0) + { + char* name; + size_t len; + + len = RTEMS_RTL_ELF_STRING_MAX; + if (!rtems_rtl_obj_cache_read (strings, fd, + sectstroff + shdr.sh_name, + (void**) &name, &len)) + return false; + + if (strcmp (".ctors", name) == 0) + flags |= RTEMS_RTL_OBJ_SECT_CTOR; + if (strcmp (".dtors", name) == 0) + flags |= RTEMS_RTL_OBJ_SECT_DTOR; + + if (!rtems_rtl_obj_add_section (obj, section, name, + shdr.sh_size, shdr.sh_offset, + shdr.sh_addralign, shdr.sh_link, + shdr.sh_info, flags)) + return false; + } + } + + return true; +} + +bool +rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd) +{ + rtems_rtl_obj_cache_t* header; + Elf_Ehdr ehdr; + + rtems_rtl_obj_caches (&header, NULL, NULL); + + if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset, + &ehdr, sizeof (ehdr))) + return false; + + /* + * Check we have a valid ELF file. + */ + if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0) + || ehdr.e_ident[EI_CLASS] != ELFCLASS) + { + return false; + } + + if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT) + || (ehdr.e_version != EV_CURRENT) + || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS))) + { + return false; + } + + return true; +} + +bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj) +{ + rtems_chain_control* sections = NULL; + rtems_chain_node* node = NULL; + size_t mask = 0; + struct link_map* l = NULL; + int sec_num = 0; + int i = 0; + + /* caculate the size of sections' name. */ + + for (mask = RTEMS_RTL_OBJ_SECT_TEXT; + mask <= RTEMS_RTL_OBJ_SECT_BSS; + mask <<= 1) + { + sections = &obj->sections; + node = rtems_chain_first (sections); + while (!rtems_chain_is_tail (sections, node)) + { + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + + if ((sect->size != 0) && ((sect->flags & mask) != 0)) + { + ++sec_num; + } + node = rtems_chain_next (node); + } + } + + obj->obj_num = 1; + obj->detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, + sizeof(struct link_map) + + sec_num * sizeof (section_detail), true); + if (!obj->detail) + { + rtems_rtl_set_error (ENOMEM, "no memory for obj global syms"); + return false; + } + + l = (struct link_map*) obj->detail; + l->name = obj->oname; + l->sec_num = sec_num; + l->sec_detail = (section_detail*) (l + 1); + l->rpathlen = 0; + l->rpath = NULL; + l->l_next = NULL; + l->l_prev = NULL; + l->sec_addr[rap_text] = obj->text_base; + l->sec_addr[rap_const] = obj->const_base; + l->sec_addr[rap_data] = obj->data_base; + l->sec_addr[rap_bss] = obj->bss_base; + + + section_detail* sd = l->sec_detail; + sections = &obj->sections; + node = rtems_chain_first (sections); + for (mask = RTEMS_RTL_OBJ_SECT_TEXT; + mask <= RTEMS_RTL_OBJ_SECT_BSS; + mask <<= 1) + { + sections = &obj->sections; + node = rtems_chain_first (sections); + while (!rtems_chain_is_tail (sections, node)) + { + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + + if ((sect->size != 0) && ((sect->flags & mask) != 0)) + { + sd[i].name = sect->name; + sd[i].size = sect->size; + if (mask == RTEMS_RTL_OBJ_SECT_TEXT) + { + sd[i].rap_id = rap_text; + sd[i].offset = sect->base - obj->text_base; + } + if (mask == RTEMS_RTL_OBJ_SECT_CONST) + { + sd[i].rap_id = rap_const; + sd[i].offset = sect->base - obj->const_base; + } + if (mask == RTEMS_RTL_OBJ_SECT_DATA) + { + sd[i].rap_id = rap_data; + sd[i].offset = sect->base - obj->data_base; + } + if (mask == RTEMS_RTL_OBJ_SECT_BSS) + { + sd[i].rap_id = rap_bss; + sd[i].offset = sect->base - obj->bss_base; + } + + ++i; + } + node = rtems_chain_next (node); + } + } + + return true; +} + +bool +rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd) +{ + rtems_rtl_obj_cache_t* header; + Elf_Ehdr ehdr; + + rtems_rtl_obj_caches (&header, NULL, NULL); + + if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset, + &ehdr, sizeof (ehdr))) + return false; + + /* + * Check we have a valid ELF file. + */ + if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0) + || ehdr.e_ident[EI_CLASS] != ELFCLASS) + { + rtems_rtl_set_error (EINVAL, "invalid ELF file format"); + return false; + } + + if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT) + || (ehdr.e_version != EV_CURRENT) + || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS))) + { + rtems_rtl_set_error (EINVAL, "unsupported ELF file version"); + return false; + } + + if (!rtems_rtl_elf_machine_check (&ehdr)) + { + rtems_rtl_set_error (EINVAL, "unsupported machine type"); + return false; + } + + if (ehdr.e_type == ET_DYN) + { + rtems_rtl_set_error (EINVAL, "unsupported ELF file type"); + return false; + } + + if (ehdr.e_phentsize != 0) + { + rtems_rtl_set_error (EINVAL, "ELF file contains program headers"); + return false; + } + + if (ehdr.e_shentsize != sizeof (Elf_Shdr)) + { + rtems_rtl_set_error (EINVAL, "invalid ELF section header size"); + return false; + } + + /* + * Parse the section information first so we have the memory map of the object + * file and the memory allocated. Any further allocations we make to complete + * the load will not fragment the memory. + */ + if (!rtems_rtl_elf_parse_sections (obj, fd, &ehdr)) + return false; + + obj->entry = (void*)(uintptr_t) ehdr.e_entry; + + if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr)) + return false; + + if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols, &ehdr)) + return false; + + if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocator, &ehdr)) + return false; + + if (!rtems_rtl_elf_load_details (obj)) + { + return false; + } + + return true; +} + +rtems_rtl_loader_format_t* +rtems_rtl_elf_file_sig (void) +{ + return &elf_sig; +} diff --git a/cpukit/libdl/rtl-elf.h b/cpukit/libdl/rtl-elf.h new file mode 100644 index 0000000000..115c05aef9 --- /dev/null +++ b/cpukit/libdl/rtl-elf.h @@ -0,0 +1,165 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker ELF Headers + */ + +#if !defined (_RTEMS_RTL_ELF_H_) +#define _RTEMS_RTL_ELF_H_ + +#include "rtl-fwd.h" +#include "rtl-obj-fwd.h" +#include "rtl-sym.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + ** Imported NetBSD ELF Specifics Start. + **/ + +/* + * Always 32bit for RTEMS at the moment. Do not add '()'. Leave plain. + */ +#define ELFSIZE 32 + +/* + * Define _STANDALONE then remove after. + */ +#define _STANDALONE 1 + +#include <sys/cdefs.h> +#include <sys/exec_elf.h> + +#undef _STANDALONE + +/** + ** Imported NetBSD ELF Specifics End. + **/ + +/** + * Maximum string length. This a read buffering limit rather than a + * specific ELF length. I hope this is ok as I am concerned about + * some C++ symbol lengths. + */ +#define RTEMS_RTL_ELF_STRING_MAX (256) + +/** + * Architecture specific handler to check is a relocation record's type is + * required to resolve a symbol. + * + * @param type The type field in the relocation record. + * @retval true The relocation record require symbol resolution. + * @retval false The relocation record does not require symbol resolution. + */ +bool rtems_rtl_elf_rel_resolve_sym (Elf_Word type); + +/** + * Architecture specific relocation handler compiled in for a specific + * architecture by the build system. The handler applies the relocation + * to the target. + * + * @param obj The object file being relocated. + * @param rel The ELF relocation record. + * @param sect The section of the object file the relocation is for. + * @param symname The symbol's name. + * @param syminfo The ELF symbol info field. + * @param symvalue If a symbol is referenced, this is the symbols value. + * @retval bool The relocation has been applied. + * @retval bool The relocation could not be applied. + */ +bool rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue); + +/** + * Architecture specific relocation handler compiled in for a specific + * architecture by the build system. The handler applies the relocation + * to the target. + * + * @param obj The object file being relocated. + * @param rela The ELF addend relocation record. + * @param sect The section of the object file the relocation is for. + * @param symname The symbol's name. + * @param syminfo The ELF symbol info field. + * @param symvalue If a symbol is referenced, this is the symbols value. + * @retval bool The relocation has been applied. + * @retval bool The relocation could not be applied. + */ +bool rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue); + +/** + * Find the symbol. The symbol is passed as an ELF type symbol with the name + * and the value returned is the absolute address of the symbol. + * + * If the symbol type is STT_NOTYPE the symbol references a global symbol. The + * gobal symbol table is searched to find it and that value returned. If the + * symbol is local to the object module the section for the symbol is located + * and it's base added to the symbol's value giving an absolute location. + * + * @param obj The object the symbol is being resolved for. + * @param sym The ELF type symbol. + * @param symname The sym's name read from the symbol string table. + * @param value Return the value of the symbol. Only valid if the return value + * is true. + * @retval true The symbol resolved. + * @retval false The symbol could not be result. The RTL error is set. + */ +bool rtems_rtl_elf_find_symbol (rtems_rtl_obj_t* obj, + const Elf_Sym* sym, + const char* symname, + Elf_Word* value); + +/** + * The ELF format check handler. + * + * @param obj The object being checked. + * @param fd The file descriptor. + */ +bool rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd); + +/** + * The ELF file details handler. + * + * @param obj Load the details of the obj. + */ +bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj); + +/** + * The ELF format load handler. + * + * @param obj The object to load. + * @param fd The file descriptor. + */ +bool rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd); + +/** + * The ELF format signature handler. + * + * @return rtems_rtl_loader_format_t* The format's signature. + */ +rtems_rtl_loader_format_t* rtems_rtl_elf_file_sig (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-error.c b/cpukit/libdl/rtl-error.c new file mode 100644 index 0000000000..bc2e3e425c --- /dev/null +++ b/cpukit/libdl/rtl-error.c @@ -0,0 +1,47 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtl + * + * @brief RTEMS Run-Time Linker Error + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdarg.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-error.h" + +void +rtems_rtl_set_error (int error, const char* format, ...) +{ + rtems_rtl_data_t* rtl = rtems_rtl_lock (); + va_list ap; + va_start (ap, format); + rtl->last_errno = error; + vsnprintf (rtl->last_error, sizeof (rtl->last_error), format, ap); + rtems_rtl_unlock (); + va_end (ap); +} + +int +rtems_rtl_get_error (char* message, size_t max_message) +{ + rtems_rtl_data_t* rtl = rtems_rtl_lock (); + int last_errno = rtl->last_errno; + strncpy (message, rtl->last_error, sizeof (rtl->last_error)); + rtems_rtl_unlock (); + return last_errno; +} + diff --git a/cpukit/libdl/rtl-error.h b/cpukit/libdl/rtl-error.h new file mode 100644 index 0000000000..a17db59adb --- /dev/null +++ b/cpukit/libdl/rtl-error.h @@ -0,0 +1,44 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Error + */ + +#if !defined (_RTEMS_RTL_ERROR_H_) +#define _RTEMS_RTL_ERROR_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if __GNUC__ +#define RTEMS_RTL_PRINTF_ATTR __attribute__((__format__(__printf__,2,3))) +#else +#define RTEMS_RTL_PRINTF_ATTR +#endif + +/** + * Sets the error. + * + * Assumes the RTL has been locked. + * + * @param error The errno error number. + * @param format The error format string. + * @param ... The variable arguments that depend on the format string. + */ +void rtems_rtl_set_error (int error, const char* format, ...) RTEMS_RTL_PRINTF_ATTR; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-find-file.c b/cpukit/libdl/rtl-find-file.c new file mode 100644 index 0000000000..589be40a10 --- /dev/null +++ b/cpukit/libdl/rtl-find-file.c @@ -0,0 +1,110 @@ +/* + * COPYRIGHT (c) 2012-2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtl + * + * @brief RTEMS Run-Time Linker Error + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#include <rtems/libio_.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-find-file.h" +#include "rtl-error.h" +#include "rtl-string.h" +#include "rtl-trace.h" + +#if WAF_BUILD +#define rtems_filesystem_is_delimiter rtems_filesystem_is_separator +#endif + +bool +rtems_rtl_find_file (const char* name, + const char* paths, + const char** file_name, + size_t* size) +{ + struct stat sb; + + *file_name = NULL; + *size = 0; + + if (rtems_filesystem_is_delimiter (name[0]) || (name[0] == '.')) + { + if (stat (name, &sb) == 0) + *file_name = rtems_rtl_strdup (name); + } + else if (paths) + { + const char* start; + const char* end; + int len; + char* fname; + + start = paths; + end = start + strlen (paths); + len = strlen (name); + + while (!*file_name && (start != end)) + { + const char* delimiter = strchr (start, ':'); + + if (delimiter == NULL) + delimiter = end; + + /* + * Allocate the path fragment, separator, name, terminating nul. Form the + * path then see if the stat call works. + */ + + fname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, + (delimiter - start) + 1 + len + 1, true); + if (!fname) + { + rtems_rtl_set_error (ENOMEM, "no memory searching for file"); + return false; + } + + memcpy (fname, start, delimiter - start); + fname[delimiter - start] = '/'; + memcpy (fname + (delimiter - start) + 1, name, len); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: find-file: path: %s\n", fname); + + if (stat (fname, &sb) < 0) + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, fname); + else + *file_name = fname; + + start = delimiter; + if (start != end) + ++start; + } + } + + if (!*file_name) + return false; + + *size = sb.st_size; + + return true; +} diff --git a/cpukit/libdl/rtl-find-file.h b/cpukit/libdl/rtl-find-file.h new file mode 100644 index 0000000000..fc8a9dcf8f --- /dev/null +++ b/cpukit/libdl/rtl-find-file.h @@ -0,0 +1,45 @@ +/* + * COPYRIGHT (c) 2012-2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object Support. + */ + +#if !defined (_RTEMS_RTL_FIND_FILE_H_) +#define _RTEMS_RTL_FIND_FILE_H_ + +#include <rtems.h> +#include <rtems/chain.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Find a file on disk given a name and a path. + * + * @param name The file name to find. Can be relative or absolute. + * @param paths The paths to search. + * @param file_name Place the full path in this location if found. + * @param size The size of the file if found as returned by the 'stat' call. + * @retval true The file was found. + * @retval false The file was not found. + */ +bool rtems_rtl_find_file (const char* name, + const char* paths, + const char** file_name, + size_t* size); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-fwd.h b/cpukit/libdl/rtl-fwd.h new file mode 100644 index 0000000000..115ba8c3bc --- /dev/null +++ b/cpukit/libdl/rtl-fwd.h @@ -0,0 +1,33 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker ELF Headers + */ + +#if !defined (_RTEMS_RTL_FWD_H_) +#define _RTEMS_RTL_FWD_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * The forward declaration of the obj structure. + */ +struct rtems_rtl_data_s; +typedef struct rtems_rtl_data_s rtems_rtl_data_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-indirect-ptr.h b/cpukit/libdl/rtl-indirect-ptr.h new file mode 100644 index 0000000000..5a5b43b9c0 --- /dev/null +++ b/cpukit/libdl/rtl-indirect-ptr.h @@ -0,0 +1,235 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Indirect Pointer Management allows memory + * compaction in the allocator. + */ + +#if !defined (_RTEMS_RTL_INDIRECT_PTR_H_) +#define _RTEMS_RTL_INDIRECT_PTR_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <rtems/chain.h> + +/** + * The RTL Indirect pointer. + */ +struct rtems_rtl_ptr_s { + rtems_chain_node node; /**< Indirect pointers are held on lists. */ + void* pointer; /**< The actual pointer. */ +}; + +typedef struct rtems_rtl_ptr_s rtems_rtl_ptr_t; + +/** + * The RTL Indirect size and pointer. + */ +struct rtems_rtl_sptr_s { + rtems_rtl_ptr_t ptr; /**< The indirect pointer. */ + size_t size; /**< The size of the memory block. */ +}; + +typedef struct rtems_rtl_sptr_s rtems_rtl_sptr_t; + +/** + * A chain of indirect pointers for users to chain in applications. + * + * @note The chain the pointer is on is internal to the allocator and cannot be + * used by applications. + */ +struct rtems_rtl_ptr_chain_s { + rtems_chain_node node; /**< Chain of indirect pointers. */ + rtems_rtl_ptr_t ptr; /**< The indirect pointer. */ +}; + +typedef struct rtems_rtl_ptr_chain_s rtems_rtl_ptr_chain_t; + +/** + * A chain of indirect sized pointers for users to chain in applications. + * + * @note The chain the pointer is on is internal to the allocator and cannot be + * used by applications. + */ +struct rtems_rtl_sptr_chain_s { + rtems_chain_node node; /**< Chain of indirect pointers. */ + rtems_rtl_sptr_t ptr; /**< The indirect pointer. */ +}; + +typedef struct rtems_rtl_sptr_chain_s rtems_rtl_sptr_chain_t; + +/** + * Get the pointer given an indirect handle. + * + * @param handle The handle the pointer is returned from. + * @return void* The pointer held in the handle. + */ +static inline void* rtems_rtl_ptr_get (rtems_rtl_ptr_t* handle) +{ + return handle->pointer; +} + +/** + * Set the pointer given an indirect handle and the pointer. + * + * @param handle The handle the pointer is returned from. + * @param pointer The pointer to set in the handle. + */ +static inline void rtems_rtl_ptr_set (rtems_rtl_ptr_t* handle, void* pointer) +{ + handle->pointer = pointer; +} + +/** + * Initialise the indirect handle. + * + * @param handle The handle to initialise. + */ +static inline void rtems_rtl_ptr_init (rtems_rtl_ptr_t* handle) +{ + rtems_chain_set_off_chain (&handle->node); + handle->pointer = NULL; +} + +/** + * Is the indirect handle NULL ? + * + * @param handle The handle to test. + * @return bool True if the pointer is NULL. + */ +static inline bool rtems_rtl_ptr_null (rtems_rtl_ptr_t* handle) +{ + return handle->pointer == NULL; +} + +/** + * Move the allocated pointer from one handle to another. The source handle is + * cleared and removed from the list of handles. + * + * @param src The source handle to move the pointer from. + * @param dst The destination handle to receive the pointer. + */ +static inline void rtems_rtl_ptr_move (rtems_rtl_ptr_t* dst, rtems_rtl_ptr_t* src) +{ + /* + * We do not know which chain the src handle resides on so insert the dst + * handle after the src handle then extract the src handle. + */ + rtems_chain_insert_unprotected (&src->node, &dst->node); + rtems_chain_extract_unprotected (&src->node); + dst->pointer = src->pointer; + rtems_rtl_ptr_init (src); +} + +/** + * Return the pointer as the type provided. + * + * @param _h The handle. + * @param _t The type. + */ +#define rtems_rtl_ptr_type_get(_h, _t) ((_t*) rtems_rtl_ptr_get (_h)) + +/** + * Get the pointer given an indirect handle. + * + * @param handle The handle the pointer is returned from. + * @return void* The pointer held in the handle. + */ +static inline void* rtems_rtl_sptr_get (rtems_rtl_sptr_t* handle) +{ + return rtems_rtl_ptr_get (&handle->ptr); +} + +/** + * Set the pointer given an indirect handle and the pointer. + * + * @param handle The handle the pointer is returned from. + * @param pointer The pointer to set in the handle. + */ +static inline void rtems_rtl_sptr_set (rtems_rtl_sptr_t* handle, void* pointer) +{ + rtems_rtl_ptr_set (&handle->ptr, pointer); +} + +/** + * Initialise the indirect handle. + * + * @param handle The handle to initialise. + */ +static inline void rtems_rtl_sptr_init (rtems_rtl_sptr_t* handle) +{ + rtems_rtl_ptr_init (&handle->ptr); + handle->size = 0; +} + +/** + * Is the indirect handle NULL ? + * + * @param handle The handle to test. + * @return bool True if the pointer is NULL. + */ +static inline bool rtems_rtl_sptr_null (rtems_rtl_sptr_t* handle) +{ + return rtems_rtl_ptr_null (&handle->ptr); +} + +/** + * Move the allocated pointer from one handle to another. The source handle is + * cleared and removed from the list of handles. + * + * @param src The source handle to move the pointer from. + * @param dst The destination handle to receive the pointer. + */ +static inline void rtems_rtl_sptr_move (rtems_rtl_sptr_t* dst, rtems_rtl_sptr_t* src) +{ + rtems_rtl_ptr_move (&dst->ptr, &src->ptr); + dst->size = src->size; + src->size = 0; +} + +/** + * Get the size. + * + * @param handle The handle to get the size from. + * @return size_t The size_t. + */ +static inline size_t rtems_rtl_sptr_get_size (rtems_rtl_sptr_t* handle) +{ + return handle->size; +} + +/** + * Set the size. + * + * @param handle The handle to set the size. + * @param size The size to set.. + */ +static inline void rtems_rtl_sptr_set_size (rtems_rtl_sptr_t* handle, size_t size) +{ + handle->size = size; +} + +/** + * Return the pointer as the type provided. + * + * @param _h The handle. + * @param _t The type. + */ +#define rtems_rtl_sptr_type_get(_h, _t) ((_t*) rtems_rtl_sptr_get (_h)) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c new file mode 100644 index 0000000000..692c8297a8 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-arm.c @@ -0,0 +1,323 @@ +/* + * Taken from NetBSD and stripped of the relocations not needed on RTEMS. + */ + +/* $NetBSD: mdreloc.c,v 1.33 2010/01/14 12:12:07 skrll Exp $ */ + +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +/* + * It is possible for the compiler to emit relocations for unaligned data. + * We handle this situation with these inlines. + */ +#define RELOC_ALIGNED_P(x) \ + (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) + +static inline Elf_Addr +load_ptr(void *where) +{ + Elf_Addr res; + + memcpy(&res, where, sizeof(res)); + + return (res); +} + +static inline void +store_ptr(void *where, Elf_Addr val) +{ + + memcpy(where, &val, sizeof(val)); +} + +/* + * The address of Thumb function symbols is it's real address plus one. + * This is done by compiler, thus do not consider symtype here. + */ +static inline int +isThumb(Elf_Word symvalue) +{ + if ((symvalue & 0x1) == 0x1) + return true; + else return false; +} + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + return false; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr *where; + Elf_Addr tmp; + Elf_Word insn, addend; + Elf_Word sign, i1, i2; + uint16_t lower_insn, upper_insn; + + where = (Elf_Addr *)(sect->base + rel->r_offset); + + switch (ELF_R_TYPE(rel->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(CALL): /* BL/BLX */ + case R_TYPE(JUMP24): /* B/BL<cond> */ + insn = *where; + + if (insn & 0x00800000) + addend = insn | 0xff000000; + else addend = insn & 0x00ffffff; + + if (isThumb(symvalue)) { + if ((insn & 0xfe000000) == 0xfa000000); /* Already blx */ + else { + if ((insn & 0xff000000) == 0xeb000000) { /* BL <label> */ + *where = (insn & 0x00ffffff) | 0xfa000000; /* BL-->BLX */ + } else { + printf("JUMP24 is not suppored from arm to thumb\n"); + return false; + } + } + } + + tmp = symvalue + (addend << 2) - (Elf_Addr)where; + tmp = (Elf_Sword)tmp >> 2; + + if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) { + printf("CALL/JUMP24 Overflow\n"); + return false; + } + + *where = (*where & 0xff000000) | (tmp & 0xffffff); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: JUMP24/PC24/CALL %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + + break; + + case R_TYPE(V4BX): + /* Miscellaneous, ignore */ + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf ("rtl: V4BX %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + } + break; + + case R_TYPE(MOVT_ABS): + case R_TYPE(MOVW_ABS_NC): + insn = *where; + + addend = ((insn >> 4) & 0xf000) | (insn & 0x0fff); + if (addend & 0x8000) + addend |= 0xffff0000; + + tmp = symvalue + addend; + + if (ELF_R_TYPE(rel->r_info) == R_TYPE(MOVW_ABS_NC)) + tmp &= 0xffff; + else { + tmp = (Elf_Sword)tmp >> 16; + if (((Elf_Sword)tmp > 0x7fff) || ((Elf_Sword)tmp < -0x8000)) { + printf("MOVT_ABS Overflow\n"); + return false; + } + } + + *where = (insn & 0xfff0f000) | ((tmp & 0xf000) << 4) | (tmp & 0xfff); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: MOVT_ABS/MOVW_ABS_NC %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + break; + + + case R_TYPE(REL32): /* word32 (S + A) | T - P */ + case R_TYPE(ABS32): /* word32 (S + A) | T */ + case R_TYPE(GLOB_DAT): /* word32 (S + A) | T */ + if (__predict_true(RELOC_ALIGNED_P(where))) { + tmp = *where + symvalue; + if (isThumb(symvalue)) + tmp |= 1; + if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32)) + tmp -= (Elf_Addr)where; + *where = tmp; + } else { + tmp = load_ptr(where) + symvalue; + if (isThumb(symvalue)) + tmp |= 1; + if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32)) + tmp -= (Elf_Addr)where; + store_ptr(where, tmp); + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: REL32/ABS32/GLOB_DAT %p @ %p in %s", + (void *)tmp, where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(THM_MOVT_ABS): + case R_TYPE(THM_MOVW_ABS_NC): + upper_insn = *(uint16_t *)where; + lower_insn = *((uint16_t *)where + 1); + + addend = ((upper_insn & 0x000f) << 12) | ((upper_insn & 0x0400) << 1) | + ((lower_insn & 0x7000) >> 4) | (lower_insn & 0x00ff); + addend = (addend ^ 0x8000) - 0x8000; + + tmp = addend + symvalue; + if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS) + tmp >>= 16; + + *(uint16_t *)where = (uint16_t)((upper_insn & 0xfbf0) | + ((tmp & 0xf000) >> 12) | + ((tmp & 0x0800) >> 1)); + *((uint16_t *)where + 1) = (uint16_t)((lower_insn & 0x8f00) | + ((tmp & 0x0700) << 4) | + (tmp & 0x00ff)); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf ("rtl: THM_MOVT_ABS/THM_MOVW_ABS_NC %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + } + + break; + + case R_TYPE(THM_JUMP24): + /* same to THM_CALL; insn b.w */ + case R_TYPE(THM_CALL): + upper_insn = *(uint16_t *)where; + lower_insn = *((uint16_t *)where + 1); + sign = (upper_insn & (1 << 10)) >> 10; + i1 = ((lower_insn >> 13) & 1) ^ sign ? 0 : 1; + i2 = ((lower_insn >> 11) & 1) ^ sign ? 0 : 1; + tmp = (i1 << 23) | (i2 << 22) | ((upper_insn & 0x3ff) << 12) | ((lower_insn & 0x7ff) << 1); + addend = (tmp | ((sign ? 0 : 1) << 24)) - (1 << 24); + + if (isThumb(symvalue)) ;/*Thumb to Thumb call, nothing to care */ + else { + if (ELF_R_TYPE(rel->r_info) == R_TYPE(THM_JUMP24)) { + tmp = (tmp + 2) & ~3; /* aligned to 4 bytes only for JUMP24 */ + printf("THM_JUMP24 to arm not supported\n"); + return false; + } + else { + /* THM_CALL bl-->blx */ + lower_insn &=~(1<<12); + } + } + + tmp = symvalue + addend; + tmp = tmp - (Elf_Addr)where; + + if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) { + printf("THM_CALL/JUMP24 overflow\n"); + return false; + } + + sign = (tmp >> 24) & 1; + *(uint16_t *)where = (uint16_t)((upper_insn & 0xf800) | (sign << 10) | + ((tmp >> 12) & 0x3ff)); + + *((uint16_t *)where + 1) = (uint16_t)((lower_insn & 0xd000)| + ((sign ^ (~(tmp >> 23) & 1)) << 13) | + ((sign ^ (~(tmp >> 22) & 1)) << 11) | + ((tmp >> 1) & 0x7ff)); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)){ + printf ("rtl: THM_CALL/JUMP24 %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + } + + break; + + case R_TYPE(THM_JUMP19): + + if (!isThumb(symvalue)) { + printf("THM_JUMP19 to arm not supported\n"); + return false; + } + + upper_insn = *(uint16_t *)where; + lower_insn = *((uint16_t *)where + 1); + sign = (upper_insn >> 10) & 0x1; + + if ((((upper_insn & 0x3f) >> 7) & 0x7) == 0x7) { + printf("THM_JUMP19 failed\n"); + return false; /*if cond <3:1> == '111', see Related codings in armv7a manual */ + } + + i1 = (lower_insn >> 13) & 0x1; + i2 = (lower_insn >> 11) & 0x1; + + tmp = ((i2 << 19) | (i1 << 18) | ((upper_insn & 0x3f) << 12) | ((lower_insn & 0x7ff) << 1)); + addend = (tmp | ((sign ? 0 : 1) << 20)) - (1 << 20); + tmp = symvalue + addend; + + tmp = tmp - (Elf_Addr)where; + + if (((Elf_Sword)tmp > 0x7ffffe) || ((Elf_Sword)tmp < -0x800000)) { + rtems_rtl_set_error (EINVAL, "%s: Overflow %ld " + "THM_JUMP19 relocations", + sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); + return false; + } + + sign = (tmp >> 20) & 0x1; + i2 = (tmp >> 19) & 0x1; + i1 = (tmp >> 18) & 0x1; + + *(uint16_t*)where = (upper_insn & 0xfbc0) | (sign << 10) | ((tmp >> 12) & 0x3f); + *((uint16_t*)where + 1) = (lower_insn & 0xd000) | (i1 << 13) | + (i2 << 11) | ((tmp >> 1) & 0x7ff); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: THM_JUMP19 %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + break; + + default: + printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " + "contents = %p\n", + ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), + (void *)rel->r_offset, (void *)*where); + rtems_rtl_set_error (EINVAL, + "%s: Unsupported relocation type %ld " + "in non-PLT relocations", + sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); + return false; + } + + return true; +} + diff --git a/cpukit/libdl/rtl-mdreloc-bfin.c b/cpukit/libdl/rtl-mdreloc-bfin.c new file mode 100644 index 0000000000..1c9fd5b956 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-bfin.c @@ -0,0 +1,115 @@ +#include <sys/cdefs.h> + +#include <stdio.h> +#include <rtl.h> +#include <errno.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +static inline Elf_Addr +load_ptr(void *where) +{ + Elf_Addr res; + + memcpy(&res, where, sizeof(res)); + + return (res); +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr target = 0; + Elf_Addr *where; + Elf_Word tmp; + Elf_Word size; //byte + + where = (Elf_Addr *)(sect->base + rela->r_offset); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf("rela relocation type is %d relocated address 0x%08x", + ELF_R_TYPE(rela->r_info), where); + } + + tmp = symvalue; + switch (ELF_R_TYPE(rela->r_info)) { + case R_TYPE(UNUSED0): + break; + + case R_TYPE(HUIMM16): + tmp = symvalue >> 16; + case R_TYPE(LUIMM16): + case R_TYPE(RIMM16): + size = 2; + break; + + case R_TYPE(BYTE4_DATA): + size = 4; + break; + + case R_TYPE(PCREL24): + case R_TYPE(PCREL24_JU): + where = (Elf_Addr*)((Elf_Addr)where - 2); /* Back 2 bytes */ + tmp = symvalue - (Elf_Addr)where; + tmp >>= 1; + if ((tmp & 0x20000000) == 0x20000000) + tmp |= 0xc0000000; + + if ((tmp & 0xff000000) && (~tmp & 0xff800000)) { + printf("PCREL24/PCREL24_JU Overflow\n"); + return false; + } + + tmp = (load_ptr(where) & 0x0000ff00) | ((tmp & 0x0000ffff) << 16) | + ((tmp & 0x00ff0000) >> 16); + size = 4; + break; + + case R_TYPE(PCREL12_JUMP_S): + tmp = symvalue - (Elf_Addr)where; + tmp >>= 1; + if ((tmp & 0x20000000) == 0x20000000) + tmp |= 0xc0000000; + + if ((tmp & 0xfffff000) && (~tmp & 0xfffff800)) { + printf("PCREL12_JUMP_S Overflow\n"); + return false; + } + + tmp = ((*(uint16_t *)where) & 0xf000) | (tmp & 0xfff); + size = 2; + break; + + default: + printf("Unspported rela type\n"); + return false; + } + + memcpy((void*)where, &tmp, size); + + return true; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rel type record not supported"); + return false; +} diff --git a/cpukit/libdl/rtl-mdreloc-h8300.c b/cpukit/libdl/rtl-mdreloc-h8300.c new file mode 100644 index 0000000000..925601b7d2 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-h8300.c @@ -0,0 +1,101 @@ +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr *where; + Elf_Word tmp; + + where = (Elf_Addr *)(sect->base + rela->r_offset); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf("rela relocation type is %ld\n", ELF_R_TYPE(rela->r_info)); + printf("relocated address 0x%08lx\n", (Elf_Addr)where); + } + + tmp = symvalue; + switch (ELF_R_TYPE(rela->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(DIR16): + *(uint16_t *)where += symvalue + rela->r_addend; + break; + + case R_TYPE(DIR32): + case R_TYPE(DIR32A16): + *where += symvalue + rela->r_addend; + break; + + case R_TYPE(DIR24A8): + if (ELF32_R_SYM(rela->r_info)) + *where += symvalue + rela->r_addend; + break; + + case R_TYPE(DIR24R8): + where = (uint32_t *)((uint32_t)where - 1); + *where = (*where & 0xff000000) | ((*where & 0xffffff) + symvalue + rela->r_addend); + break; + + case R_TYPE(PCREL8): + /* bcc instruction */ + tmp = symvalue + rela->r_addend - (Elf_Addr)where - 1; + if (((Elf32_Sword)tmp > 0x7f) || ((Elf32_Sword)tmp < -(Elf32_Sword)0x80)){ + printf("PCREL8 overflow\n"); + return false; + } else { + *(uint8_t *)where = tmp; + } + break; + + case R_TYPE(PCREL16): + /* bcc instruction */ + tmp = symvalue + rela->r_addend - (Elf_Addr)where - 2; + if (((Elf32_Sword)tmp > 0x7fff) || ((Elf32_Sword)tmp < -(Elf32_Sword)0x8000)){ + printf("PCREL16 overflow\n"); + return false; + } else { + *(uint16_t *)where = tmp; + } + break; + + default: + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + printf("Unsupported reloc types\n"); + return false; + } + return true; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rel type record not supported"); + return false; +} diff --git a/cpukit/libdl/rtl-mdreloc-i386.c b/cpukit/libdl/rtl-mdreloc-i386.c new file mode 100644 index 0000000000..b6dd9b7306 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-i386.c @@ -0,0 +1,103 @@ +/* + * Taken from NetBSD and stripped of the relocations not needed on RTEMS. + */ + +/* $NetBSD: mdreloc.c,v 1.31 2010/01/14 11:58:32 skrll Exp $ */ + +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + return false; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr target = 0; + Elf_Addr* where; + Elf_Addr tmp; + + where = (Elf_Addr *)(sect->base + rel->r_offset); + + switch (ELF_R_TYPE(rel->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(PC32): + target = (Elf_Addr) symvalue; + *where += target - (Elf_Addr)where; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc PC32 in %s --> %p (%p @ %p) in %s\n", + sect->name, (void*) symvalue, + (void *)*where, where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(GOT32): + case R_TYPE(32): + case R_TYPE(GLOB_DAT): + target = (Elf_Addr) symvalue; + + tmp = target + *where; + if (*where != tmp) + *where = tmp; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc 32/GLOB_DAT in %s --> %p @ %p in %s\n", + sect->name, (void *)*where, where, + rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(RELATIVE): + *where += (Elf_Addr)sect->base; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc RELATIVE in %s --> %p @ %p\n", + rtems_rtl_obj_oname (obj), (void *)*where, where); + break; + + case R_TYPE(COPY): + printf ("rtl: reloc COPY (please report)\n"); + break; + + default: + printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " + "contents = %p\n", + ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), + (void *)rel->r_offset, (void *)*where); + rtems_rtl_set_error (EINVAL, + "%s: Unsupported relocation type %ld " + "in non-PLT relocations", + sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); + return false; + } + + return true; +} diff --git a/cpukit/libdl/rtl-mdreloc-lm32.c b/cpukit/libdl/rtl-mdreloc-lm32.c new file mode 100644 index 0000000000..057d6ce6dd --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-lm32.c @@ -0,0 +1,120 @@ +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr *where; + Elf32_Word tmp; + Elf32_Word insn; + + + where = (Elf_Addr *)(sect->base + rela->r_offset); + + switch (ELF_R_TYPE(rela->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(HI16): + insn = *where; + /* orhi/mvhi instruction + * 31--------26|25-21|20-16|15----0| + * |0 1 1 1 1 0 |rY |rX |imm16 | + */ + if (0x1e == (insn >> 26)) { + insn &= 0xffff0000; + insn |= ((symvalue + rela->r_addend) >> 16); + *where = insn; + } + break; + + case R_TYPE(LO16): + insn = *where; + /* ori instruction + * 31--------26|25-21|20-16|15----0| + * |0 0 1 1 1 0 |rY |rX |imm16 | + */ + if (0xe == (insn >> 26)) { + insn &= 0xffff0000; + insn |= ((symvalue + rela->r_addend) & 0xffff); + *where = insn; + } + break; + + case R_TYPE(CALL): + insn = *where; + /* + * calli instruction + * 31-------26|25---0| + * |1 1 1 1 1 0|imm26 | + * Syntax: call imm26 + * Operation: ra = pc + 4; pc = pc + sign_extend(imm26<<2) + */ + if (0x3e == (insn >> 26)) { + Elf_Sword imm26 = symvalue +rela->r_addend - (Elf_Addr)where; + imm26 = (imm26 >> 2) & 0x3ffffff; + insn = 0xf8000000 + imm26; + *where = insn; + } + break; + + case R_TYPE(BRANCH): + insn = *where; + tmp = symvalue + rela->r_addend - (Elf_Addr)where; + tmp = (Elf32_Sword)tmp >> 2; + if (((Elf32_Sword)tmp > 0x7fff) || ((Elf32_Sword)tmp < -0x8000)){ + printf("BRANCH Overflow\n"); + return false; + } + + *where = (*where & 0xffff0000) | (tmp & 0xffff); + break; + + case R_TYPE(32): + *where = symvalue + rela->r_addend; + break; + + default: + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + printf("Unsupported reloc types\n"); + return false; + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf("rela relocation type is %ld\n", ELF_R_TYPE(rela->r_info)); + printf("relocated address 0x%08lx\n", (Elf_Addr)where); + } + return true; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + return false; +} diff --git a/cpukit/libdl/rtl-mdreloc-m32r.c b/cpukit/libdl/rtl-mdreloc-m32r.c new file mode 100644 index 0000000000..de32f06896 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-m32r.c @@ -0,0 +1,156 @@ +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +static inline Elf_Addr +load_ptr(void *where) +{ + Elf_Addr res; + + memcpy(&res, where, sizeof(res)); + + return (res); +} + +static inline void +store_ptr(void *where, Elf_Addr val) +{ + memcpy(where, &val, sizeof(val)); +} + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + + Elf_Addr *where; + Elf_Word tmp; + + where = (Elf_Addr *)(sect->base + rela->r_offset); + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf("relocated address 0x%08lx\n", (Elf_Addr)where); + } + + switch (ELF_R_TYPE(rela->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(16_RELA): + /* + * half16: S + A + */ + *(uint16_t *)where = (symvalue + rela->r_addend) & 0xffff; + break; + + case R_TYPE(24_RELA): + /* + * imm24: (S + A) & 0xFFFFFF + */ + tmp = symvalue + rela->r_addend; + if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) { + printf("24_RELA Overflow\n"); + return false; + } + *where = (*where & 0xff000000) | tmp & 0xffffff; + break; + + case R_TYPE(32_RELA): + /* + * word32: S + A + */ + *where += symvalue + rela->r_addend; + break; + + case R_TYPE(26_PCREL_RELA): + /* + * disp24: ((S + A - P) >> 2) & 0xFFFFFF + */ + tmp = symvalue + rela->r_addend - (Elf_Addr)where; + tmp = (Elf_Sword)tmp >> 2; + if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) { + printf("26_PCREL_RELA Overflow\n"); + return false; + } + + *where = (*where & 0xff000000) | (tmp & 0xffffff); + break; + + case R_TYPE(18_PCREL_RELA): + /* + * disp16: ((S + A - P) >> 2) & 0xFFFFFF + */ + tmp = symvalue + rela->r_addend - (Elf_Addr)where; + tmp = (Elf_Sword)tmp >> 2; + if (((Elf_Sword)tmp > 0x7fff) || ((Elf_Sword)tmp < -0x8000)) { + printf("18_PCREL_RELA Overflow\n"); + return false; + } + + *where = (*where & 0xffff0000) | (tmp & 0xffff); + break; + + case R_TYPE(HI16_ULO_RELA): + /* + * imm16: ((S + A) >> 16) + */ + tmp = *where; + tmp += ((symvalue + rela->r_addend) >> 16) & 0xffff; + *where = tmp; + break; + + case R_TYPE(HI16_SLO_RELA): + /* + * imm16: ((S + A) >> 16) or ((S + A + 0x10000) >> 16) + */ + tmp = symvalue + rela->r_addend; + if (tmp & 0x8000) tmp += 0x10000; + tmp = (tmp >> 16) & 0xffff; + *where += tmp; + break; + + case R_TYPE(LO16_RELA): + /* + * imm16: (S + A) & 0xFFFF + */ + tmp = symvalue + rela->r_addend; + *where = (*where & 0xffff0000) | (tmp & 0xffff); + break; + + default: + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + printf("Unsupported rela reloc types\n"); + return false; + } + return true; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + + rtems_rtl_set_error (EINVAL, "rel type record not supported"); + return true; +} diff --git a/cpukit/libdl/rtl-mdreloc-m68k.c b/cpukit/libdl/rtl-mdreloc-m68k.c new file mode 100644 index 0000000000..36692ebf85 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-m68k.c @@ -0,0 +1,148 @@ +/* + * Taken from NetBSD and stripped of the relocations not needed on RTEMS. + */ + +/* $NetBSD: mdreloc.c,v 1.26 2010/01/14 11:58:32 skrll Exp $ */ + +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +static inline int overflow_8_check(int value) +{ + if ((value & 0xffffff00) && (~value & 0xffffff80)) + return true; + return false; +} + +static inline int overflow_16_check(int value) +{ + if ((value & 0xffff0000) && (~value & 0xffff8000)) + return true; + return false; +} + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symnane, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr target = 0; + Elf_Addr* where; + Elf_Word tmp; + + where = (Elf_Addr *)(sect->base + rela->r_offset); + + switch (ELF_R_TYPE(rela->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(PC8): + tmp = symvalue + rela->r_addend - (Elf_Addr)where; + if (overflow_8_check(tmp)) + return false; + + *(uint8_t *)where = tmp; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc R_TYPE_8/PC8 in %s --> %p (%p) in %s\n", + sect->name, (void*) (symvalue + rela->r_addend), + (void *)*where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(PC16): + tmp = symvalue + rela->r_addend - (Elf_Addr)where; + if (overflow_16_check(tmp)) + return false; + + *(uint16_t*)where = tmp; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc R_TYPE_16/PC16 in %s --> %p (%p) in %s\n", + sect->name, (void*) (symvalue + rela->r_addend), + (void *)*where, rtems_rtl_obj_oname (obj)); + break; + case R_TYPE(PC32): + target = (Elf_Addr) symvalue + rela->r_addend; + *where += target - (Elf_Addr)where; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc PC32 in %s --> %p (%p) in %s\n", + sect->name, (void*) (symvalue + rela->r_addend), + (void *)*where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(GOT32): + case R_TYPE(32): + case R_TYPE(GLOB_DAT): + target = (Elf_Addr) symvalue + rela->r_addend; + + if (*where != target) + *where = target; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc 32/GLOB_DAT in %s --> %p in %s\n", + sect->name, (void *)*where, + rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(RELATIVE): + *where += (Elf_Addr) sect->base + rela->r_addend; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc RELATIVE in %s --> %p\n", + rtems_rtl_obj_oname (obj), (void *)*where); + break; + + case R_TYPE(COPY): + /* + * These are deferred until all other relocations have + * been done. All we do here is make sure that the + * COPY relocation is not in a shared library. They + * are allowed only in executable files. + */ + printf ("rtl: reloc COPY (please report)\n"); + break; + + default: + printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " + "contents = %p\n", + ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info), + (void *)rela->r_offset, (void *)*where); + rtems_rtl_set_error (EINVAL, + "%s: Unsupported relocation type %ld " + "in non-PLT relocations", + sect->name, (uint32_t) ELF_R_TYPE(rela->r_info)); + return false; + } + + return true; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rel type record not supported"); + return false; +} diff --git a/cpukit/libdl/rtl-mdreloc-mips.c b/cpukit/libdl/rtl-mdreloc-mips.c new file mode 100644 index 0000000000..ea9989a475 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-mips.c @@ -0,0 +1,190 @@ +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + return false; +} + +/* + * 1. _gp_disp symbol are not considered in this file. + * 2. There is a local/external column; + * local corresponds to (STB_LOCAL & STT_SECTION) and + * all others are external. Because if the type of a + * symbol is STT_SECTION, it must be STB_LOCAL. Thus + * just consider symtype here. + */ +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr *where; + Elf_Word tmp; + Elf_Word addend = (Elf_Word)0; + Elf_Word local = 0; + uint32_t t; + + + static Elf_Addr *where_hi16; + static Elf_Addr ahl; + + where = (Elf_Addr *)(sect->base + rel->r_offset); + addend = *where; + + if (syminfo == STT_SECTION) + local = 1; + + switch (ELF_R_TYPE(rel->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(16): + tmp = addend & 0xffff; + if ((tmp & 0x8000) == 0x8000) + tmp |= 0xffff0000; /* Sign extend */ + tmp = symvalue + (int)tmp; + if ((tmp & 0xffff0000) != 0) { + printf("R_MIPS_16 Overflow\n"); + return false; + } + + *where = (tmp & 0xffff) | (*where & 0xffff0000); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: R_MIPS_16 %p @ %p in %s\n", + (void *)*(where), where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(32): + tmp = symvalue + addend; + if (addend != tmp) + *where = tmp; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: R_MIPS_32 %p @ %p in %s\n", + (void *)*(where), where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(26): + + addend &= 0x03ffffff; + addend <<= 2; + + if (local == 1) { /* STB_LOCAL and STT_SECTION */ + tmp = symvalue + (((Elf_Addr)where & 0xf0000000) | addend); + tmp >>= 2; + + } else { /* external */ + + tmp = addend; + + if ((tmp & 0x08000000) == 0x08000000) + tmp |= 0xf0000000; /* Sign extened */ + tmp = ((int)tmp + symvalue) >> 2; + + } + + *where &= ~0x03ffffff; + *where |= tmp & 0x03ffffff; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: R_MIPS_26 local=%d %p @ %p in %s\n", + local, (void *)*(where), where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(HI16): + ahl = addend << 16; + where_hi16 = where; + + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: R_MIPS_HI16 %p @ %p in %s\n", + (void *)*(where), where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(LO16): + //ahl += (int16_t)addend; + t = ahl + (int16_t)addend; + tmp = symvalue; + if (tmp == 0) + return false; + + addend &= 0xffff0000; + addend |= (uint16_t)(t + tmp); + *where = addend; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf("*where %x where %x\n", *where, where); + + addend = *where_hi16; + addend &= 0xffff0000; + addend |= ((t + tmp) - (int16_t)(t + tmp)) >> 16; + *where_hi16 = addend; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf("*where_hi %x where_hi %x\n", *where_hi16, where_hi16); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: R_MIPS_LO16 %p @ %p in %s\n", + (void *)*(where), where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(PC16): + tmp = addend & 0xffff; + if ((tmp & 0x8000) == 0x8000) + tmp |= 0xffff0000; /* Sign extend */ + tmp = symvalue + ((int)tmp*4) - (Elf_Addr)where; + tmp = (Elf_Sword)tmp >> 2; + if (((Elf_Sword)tmp > 0x7fff) || ((Elf_Sword)tmp < -0x8000)) { + printf("R_MIPS_PC16 Overflow\n"); + return false; + } + + *where = (tmp & 0xffff) | (*where & 0xffff0000); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: R_MIPS_PC16 %p @ %p in %s\n", + (void *)*(where), where, rtems_rtl_obj_oname (obj)); + + break; + + default: + printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " + "contents = %p\n", + ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), + (void *)rel->r_offset, (void *)*where); + rtems_rtl_set_error (EINVAL, + "%s: Unsupported relocation type %ld " + "in non-PLT relocations", + sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); + return false; + } + + return true; +} diff --git a/cpukit/libdl/rtl-mdreloc-moxie.c b/cpukit/libdl/rtl-mdreloc-moxie.c new file mode 100644 index 0000000000..284f68e260 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-moxie.c @@ -0,0 +1,88 @@ + +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr *where; + Elf_Sword tmp; + + where = (Elf_Addr *)(sect->base + rela->r_offset); + + /* Handle the not 4byte aligned address carefully */ + + switch (ELF_R_TYPE(rela->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(32): + *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff; + *((uint16_t *)where + 1) = (symvalue + rela->r_addend) & 0xffff; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf("*where 0x%04x%04x\n", *((uint16_t *)where + 1), *(uint16_t *)where); + } + break; + + case R_TYPE(PCREL10): + /* beq, bge, bgeu, bgt, bgtu, ble, bleu, blt, bltu, bne */ + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf("*where %x\n", *(uint16_t *)where); + printf("symvalue - where %x\n", (int)(symvalue - (Elf_Word)where)); + } + tmp = (symvalue + rela->r_addend - ((Elf_Word)where + 2)); /* pc is the next instruction */ + tmp = (Elf_Sword)tmp >> 1; + if (((Elf32_Sword)tmp > 0x1ff) || ((Elf32_Sword)tmp < -(Elf32_Sword)0x200)){ + printf("Overflow for PCREL10: %d exceed -0x200:0x1ff\n", tmp); + return false; + } + + *(uint16_t *)where = (*(uint16_t *)where & 0xfc00) | (tmp & 0x3ff); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf("*where 0x%04x\n", *(uint16_t *)where); + } + + break; + + default: + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + printf("Unsupported reloc types\n"); + return false; + } + + return true; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rel type record not supported"); + return false; +} diff --git a/cpukit/libdl/rtl-mdreloc-nios2.c b/cpukit/libdl/rtl-mdreloc-nios2.c new file mode 100644 index 0000000000..4f63f07f98 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-nios2.c @@ -0,0 +1,44 @@ +/* + * Taken from NetBSD and stripped of the relocations not needed on RTEMS. + */ + +/* $NetBSD: mdreloc.c,v 1.26 2010/01/14 11:58:32 skrll Exp $ */ + +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + + +bool +rtems_rtl_elf_relocate_rela (rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + rtems_rtl_obj_sect_t* sect, + Elf_Word symvalue) +{ + + return true; +} + +bool +rtems_rtl_elf_relocate_rel (rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + rtems_rtl_obj_sect_t* sect, + Elf_Word symvalue) +{ + printf ("rtl: rel type record not supported; please report\n"); + return false; +} diff --git a/cpukit/libdl/rtl-mdreloc-powerpc.c b/cpukit/libdl/rtl-mdreloc-powerpc.c new file mode 100644 index 0000000000..d1c0a4fa4e --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-powerpc.c @@ -0,0 +1,186 @@ +/* + * Taken from NetBSD and stripped of the relocations not needed on RTEMS. + */ + +/* $NetBSD: ppc_reloc.c,v 1.44 2010/01/13 20:17:22 christos Exp $ */ + +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +#define ha(x) ((((u_int32_t)(x) & 0x8000) ? \ + ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16) +#define l(x) ((u_int32_t)(x) & 0xffff) + + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr target = 0; + Elf_Addr* where; + Elf_Word tmp; + uint32_t mask = 0; + uint32_t bits = 0; + + where = (Elf_Addr *)(sect->base + rela->r_offset); + switch (ELF_R_TYPE(rela->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(32): + /* + * value:1; Field: word32; Expression: S + A + */ + *where = symvalue + rela->r_addend; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: ADDR32 %p @ %p in %s\n", + (void *)*(where), where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(14): + /* + * value:7; Field: low14*; Expression: (S + A) >> 2 + */ + case R_TYPE(24): + /* + * value:2; Field: low24*; Expression: (S + A) >> 2 + */ + if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) { + bits = 14; + mask = 0xfffc; + } else { + bits = 24; + mask = 0x3fffffc; + } + tmp = (symvalue + rela->r_addend) >> 2; + if (tmp > (1<<bits -1 )) { + printf("Overflow ADDR14/ADDR24\n"); + return false; + } + tmp = *where; + tmp &= ~mask; + tmp |= (symvalue + rela->r_addend) & mask; + *where = tmp; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: ADDR14/ADDR24 %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(16_HA): + /* + * value:6; Field:half16; Expression: #ha(S+A) + */ + + tmp = symvalue + rela->r_addend; + *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff); + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: 16_HA %p @ %p in %s\n", + (void *)*(where), where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(16_HI): + /* + * value:5; Field:half16; Expression: #hi(S+A) + */ + *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: 16_HI %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + break; + case R_TYPE(16_LO): + /* + * value:4; Field:half16; Expression: #lo(S+A) + */ + *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: 16_LO %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(REL14): + /* + * value:11; Field:low14*; Expression:(S+A-P)>>2 + */ + case R_TYPE(REL24): + /* + * value:10; Field:low24*; Expression:(S+A-P)>>2 + */ + if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) { + mask = 0x3fffffc; + bits = 24; + } + else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) { + mask = 0xfffc; + bits = 14; + } + + tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2; + if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) || + ((Elf_Sword)tmp < -(1<<(bits-1)))) { + printf("Overflow REL14/REL24\n"); + return false; + } + + tmp = *where; + tmp &= ~mask; + tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask; + *where = tmp; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: REL24/REL14 %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + break; + + case R_TYPE(REL32): + /* + * value:26; Field:word32*; Expression:S+A-P + */ + *where = symvalue + rela->r_addend - (Elf_Addr)where; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: REL32 %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + break; + + default: + printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " + "contents = %p\n", + ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info), + (void *)rela->r_offset, (void *)*where); + rtems_rtl_set_error (EINVAL, + "%s: Unsupported relocation type %ld " + "in non-PLT relocations", + sect->name, (uint32_t) ELF_R_TYPE(rela->r_info)); + return false; + } + return true; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + printf ("rtl: rel type record not supported; please report\n"); + return false; +} diff --git a/cpukit/libdl/rtl-mdreloc-sparc.c b/cpukit/libdl/rtl-mdreloc-sparc.c new file mode 100644 index 0000000000..a8bf5e15ae --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-sparc.c @@ -0,0 +1,261 @@ +/* + * Taken from NetBSD and stripped of the relocations not needed on RTEMS. + */ + +/* $NetBSD: mdreloc.c,v 1.43 2010/01/13 20:17:22 christos Exp $ */ + +/*- + * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Paul Kranenburg and by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <stdio.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +/* + * The following table holds for each relocation type: + * - the width in bits of the memory location the relocation + * applies to (not currently used) + * - the number of bits the relocation value must be shifted to the + * right (i.e. discard least significant bits) to fit into + * the appropriate field in the instruction word. + * - flags indicating whether + * * the relocation involves a symbol + * * the relocation is relative to the current position + * * the relocation is for a GOT entry + * * the relocation is relative to the load address + * + */ +#define _RF_S 0x80000000 /* Resolve symbol */ +#define _RF_A 0x40000000 /* Use addend */ +#define _RF_P 0x20000000 /* Location relative */ +#define _RF_G 0x10000000 /* GOT offset */ +#define _RF_B 0x08000000 /* Load address relative */ +#define _RF_U 0x04000000 /* Unaligned */ +#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ +#define _RF_RS(s) ( (s) & 0xff) /* right shift */ + +static const uint32_t reloc_target_flags[] = { + 0, /* NONE */ + _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */ + _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELOC_32 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* DISP_8 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* DISP_16 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HI22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 13 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LO10 */ + _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */ + _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */ + _RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */ + _RF_SZ(32) | _RF_RS(0), /* COPY */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */ + _RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */ + _RF_A| _RF_B|_RF_SZ(32) | _RF_RS(0), /* RELATIVE */ + _RF_S|_RF_A| _RF_U|_RF_SZ(32) | _RF_RS(0), /* UA_32 */ +}; + +#define NOT_CURRENTLY_USED_BUT_MAYBE_USEFUL +#ifdef NOT_CURRENTLY_USED_BUT_MAYBE_USEFUL +static const char *reloc_names[] = { + "NONE", "RELOC_8", "RELOC_16", "RELOC_32", "DISP_8", + "DISP_16", "DISP_32", "WDISP_30", "WDISP_22", "HI22", + "22", "13", "LO10", "GOT10", "GOT13", + "GOT22", "PC10", "PC22", "WPLT30", "COPY", + "GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32" +}; +#endif + +#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) +#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) +#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) +#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) +#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) +#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) +#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) + +static const int reloc_target_bitmask[] = { +#define _BM(x) (~(-(1ULL << (x)))) + 0, /* NONE */ + _BM(8), _BM(16), _BM(32), /* RELOC_8, _16, _32 */ + _BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */ + _BM(30), _BM(22), /* WDISP30, WDISP22 */ + _BM(22), _BM(22), /* HI22, _22 */ + _BM(13), _BM(10), /* RELOC_13, _LO10 */ + _BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */ + _BM(10), _BM(22), /* _PC10, _PC22 */ + _BM(30), 0, /* _WPLT30, _COPY */ + -1, -1, -1, /* _GLOB_DAT, JMP_SLOT, _RELATIVE */ + _BM(32) /* _UA32 */ +#undef _BM +}; +#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return RELOC_RESOLVE_SYMBOL (type) ? true : false; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr *where; + Elf_Word type, value, mask; + + where = (Elf_Addr *) (sect->base + rela->r_offset); + + type = ELF_R_TYPE(rela->r_info); + if (type == R_TYPE(NONE)) + return true; + + /* We do JMP_SLOTs in _rtld_bind() below */ + if (type == R_TYPE(JMP_SLOT)) + return true; + + /* COPY relocs are also handled elsewhere */ + if (type == R_TYPE(COPY)) + return true; + + /* + * We use the fact that relocation types are an `enum' + * Note: R_SPARC_6 is currently numerically largest. + */ + if (type > R_TYPE(6)) + return false; + + value = rela->r_addend; + + /* + * Handle relative relocs here, as an optimization. + */ + if (type == R_TYPE (RELATIVE)) { + *where += (Elf_Addr)(sect->base + value); + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc relative in %s --> %p", + rtems_rtl_obj_oname (obj), (void *)*where); + return true; + } + + if (RELOC_RESOLVE_SYMBOL (type)) { + /* Add in the symbol's absolute address */ + value += symvalue; + } + + if (RELOC_PC_RELATIVE (type)) { + value -= (Elf_Word)where; + } + + if (RELOC_BASE_RELATIVE (type)) { + /* + * Note that even though sparcs use `Elf_rela' + * exclusively we still need the implicit memory addend + * in relocations referring to GOT entries. + * Undoubtedly, someone f*cked this up in the distant + * past, and now we're stuck with it in the name of + * compatibility for all eternity.. + * + * In any case, the implicit and explicit should be + * mutually exclusive. We provide a check for that + * here. + */ +#define DIAGNOSTIC +#ifdef DIAGNOSTIC + if (value != 0 && *where != 0) { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf("rtl: reloc base_rel(%s): where=%p, *where 0x%lx, " + "addend=0x%lx, base %p\n", + rtems_rtl_obj_oname (obj), + where, *where, rela->r_addend, sect->base); + } +#endif + value += (Elf_Word)(sect->base + *where); + } + + mask = RELOC_VALUE_BITMASK (type); + value >>= RELOC_VALUE_RIGHTSHIFT (type); + value &= mask; + + if (RELOC_UNALIGNED(type)) { + /* Handle unaligned relocations. */ + Elf_Addr tmp = 0; + char *ptr = (char *)where; + int i, size = RELOC_TARGET_SIZE (type) / 8; + + /* Read it in one byte at a time. */ + for (i=0; i<size; i++) + tmp = (tmp << 8) | ptr[i]; + + tmp &= ~mask; + tmp |= value; + + /* Write it back out. */ + for (i=0; i<size; i++) + ptr[i] = ((tmp >> (8*i)) & 0xff); + + } else { + *where &= ~mask; + *where |= value; + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: %s %p @ %p in %s\n", + reloc_names[type], (void *)*where, where, rtems_rtl_obj_oname (obj)); + + + return true; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + printf ("rtl: rel type record not supported; please report\n"); + return false; +} diff --git a/cpukit/libdl/rtl-mdreloc-v850.c b/cpukit/libdl/rtl-mdreloc-v850.c new file mode 100644 index 0000000000..5372e81e8d --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-v850.c @@ -0,0 +1,97 @@ + +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-trace.h" + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +bool +rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + Elf_Addr *where; + Elf_Word tmp; + + where = (Elf_Addr *)(sect->base + rela->r_offset); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf("rela relocation type is %ld\n", ELF_R_TYPE(rela->r_info)); + printf("relocated address 0x%08lx\n", (Elf_Addr)where); + } + + switch (ELF_R_TYPE(rela->r_info)) { + case R_TYPE(NONE): + break; + + case R_TYPE(HI16_S): + tmp = (Elf_Sword)(symvalue + rela->r_addend) >> 16; + ((uint16_t *)where)[0] = tmp & 0xffff; + break; + + case R_TYPE(LO16): + tmp = symvalue + rela->r_addend; + ((uint16_t *)where)[0] = tmp & 0xffff; + break; + + case R_TYPE(LO16_S1): + tmp = symvalue + rela->r_addend; + ((uint16_t *)where)[0] = tmp & 0xfffe | 0x1; + break; + + case R_TYPE(22_PCREL): + tmp = symvalue + rela->r_addend - (Elf_Addr)where; + if (((Elf_Sword)tmp > 0x1fffff) || ((Elf_Sword)tmp < -0x200000)) { + printf("Overflow\n"); + return false; + } + + ((uint16_t *)where)[0] = (*(uint16_t *)where & 0xffc0) | + ((tmp >> 16) & 0x3f); + ((uint16_t *)where)[1] = (tmp & 0xfffe); + + break; + + case R_TYPE(ABS32): + tmp = symvalue + rela->r_addend; + tmp += ((uint16_t *)where)[0]; + tmp += ((uint16_t *)where)[1] << 16; + ((uint16_t *)where)[0] = tmp & 0xffff; + ((uint16_t *)where)[1] = (tmp >> 16) & 0xffff; + break; + + default: + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + printf("error reloc type\n"); + return false; + } + + return true; +} + +bool +rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect_t* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rel type record not supported"); + return false; +} diff --git a/cpukit/libdl/rtl-obj-cache.c b/cpukit/libdl/rtl-obj-cache.c new file mode 100644 index 0000000000..23d7d07c43 --- /dev/null +++ b/cpukit/libdl/rtl-obj-cache.c @@ -0,0 +1,197 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object File cache buffers a section of the + * object file in a buffer to localise read performance. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include <rtems/rtl/rtl-allocator.h> +#include "rtl-obj-cache.h" +#include "rtl-error.h" + +bool +rtems_rtl_obj_cache_open (rtems_rtl_obj_cache_t* cache, size_t size) +{ + cache->fd = -1; + cache->file_size = 0; + cache->offset = 0; + cache->size = size; + cache->level = 0; + cache->buffer = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, false); + if (!cache->buffer) + { + rtems_rtl_set_error (ENOMEM, "no memory for cache buffer"); + return false; + } + return true; +} + +void +rtems_rtl_obj_cache_close (rtems_rtl_obj_cache_t* cache) +{ + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, cache->buffer); + cache->fd = -1; + cache->file_size = 0; + cache->level = 0; +} + +void +rtems_rtl_obj_cache_flush (rtems_rtl_obj_cache_t* cache) +{ + cache->fd = -1; + cache->file_size = 0; + cache->level = 0; +} + +bool +rtems_rtl_obj_cache_read (rtems_rtl_obj_cache_t* cache, + int fd, + off_t offset, + void** buffer, + size_t* length) +{ + struct stat sb; + + if (*length > cache->size) + { + rtems_rtl_set_error (EINVAL, "read size larger than cache size"); + return false; + } + + if (cache->fd == fd) + { + if (offset > cache->file_size) + { + rtems_rtl_set_error (EINVAL, "offset past end of file: offset=%i size=%i", + (int) offset, (int) cache->file_size); + return false; + } + + if ((offset + *length) > cache->file_size) + *length = cache->file_size - offset; + } + + while (true) + { + size_t buffer_offset = 0; + size_t buffer_read = cache->size; + + /* + * Is the data in the cache for this file ? + */ + if (fd == cache->fd) + { + /* + * Is any part of the data in the cache ? + */ + if ((offset >= cache->offset) && + (offset < (cache->offset + cache->level))) + { + buffer_offset = offset - cache->offset; + + /* + * Return the location of the data in the cache. + */ + *buffer = cache->buffer + buffer_offset; + + /* + * Is all the data in the cache or just a part ? + */ + if (*length <= (cache->level - buffer_offset)) + { + return true; + } + + /* + * Copy down the data in the buffer and then fill the remaining + * space with as much data we are able to read. + */ + memmove (cache->buffer, + cache->buffer + buffer_offset, + cache->size - buffer_offset); + + buffer_read = buffer_offset; + buffer_offset = cache->size - buffer_offset; + } + } + + if (lseek (fd, offset + buffer_offset, SEEK_SET) < 0) + { + rtems_rtl_set_error (errno, "file seek failed"); + return false; + } + + /* + * Loop reading the data from the file until either an error or 0 is + * returned and if data has been read check if the amount is what we + * want. If not it is an error. A POSIX read can read data in fragments. + */ + cache->level = buffer_read; + while (buffer_read) + { + int r = read (fd, cache->buffer + buffer_offset, buffer_read); + if (r < 0) + { + rtems_rtl_set_error (errno, "file read failed"); + return false; + } + if ((r == 0) && buffer_read) + { + cache->level = cache->level - buffer_read; + buffer_read = 0; + } + else + { + buffer_read -= r; + buffer_offset += r; + } + } + + cache->fd = fd; + cache->offset = offset; + + if (fstat (cache->fd, &sb) < 0) + { + rtems_rtl_set_error (errno, "file stat failed"); + return false; + } + + cache->file_size = sb.st_size; + } + + return false; +} + +bool +rtems_rtl_obj_cache_read_byval (rtems_rtl_obj_cache_t* cache, + int fd, + off_t offset, + void* buffer, + size_t length) +{ + void* cbuffer = 0; + size_t len = length; + bool ok = rtems_rtl_obj_cache_read (cache, fd, offset, &cbuffer, &len); + if (ok && (len != length)) + ok = false; + if (ok) + memcpy (buffer, cbuffer, length); + return ok; +} diff --git a/cpukit/libdl/rtl-obj-cache.h b/cpukit/libdl/rtl-obj-cache.h new file mode 100644 index 0000000000..8abb7f3187 --- /dev/null +++ b/cpukit/libdl/rtl-obj-cache.h @@ -0,0 +1,132 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object File cache buffers a section of the + * object file in a buffer to localise read performance. + * + * This is a simple object file cache that holds a buffer of data from the + * offset in the file the read is requested from. Writes are not supported. + * + * The cache holds the file descriptor, the offset into the file and the amount + * of valid data in the cache. If the file is ever modified the user of the + * cache to responsible for flushing the cache. For example the cache should be + * flused if the file is closed. + * + * The cache can return by reference or by value. By reference allow access to + * the cache buffer. Do not modify the cache's data. By value will copy the + * requested data into the user supplied buffer. + * + * The read by reference call allows you to probe the file's data. For example + * a string in an object file can be an unknown length. You can request a read + * up to the cache's size by reference. The code will attempt to have this data + * in the buffer. If there is not enough data in the file the length will be + * modifed to reflect this. + * + * You can have more than one cache for a single file all looking at different + * parts of the file. + */ + +#if !defined (_RTEMS_RTL_OBJ_CACHE_H_) +#define _RTEMS_RTL_OBJ_CACHE_H_ + +#include <fcntl.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * The buffer cache. + */ +typedef struct rtems_rtl_obj_cache_s +{ + int fd; /**< The file descriptor of the data in the cache. */ + size_t file_size; /**< The size of the file. */ + off_t offset; /**< The base offset of the buffer. */ + size_t size; /**< The size of the cache. */ + size_t level; /**< The amount of data in the cache. A file can be + * smaller than the cache file. */ + uint8_t* buffer; /**< The buffer */ +} rtems_rtl_obj_cache_t; + +/** + * Open a cache allocating a single buffer of the size passed. The default + * state of the cache is flushed. No already open checks are made. + * + * @param cache The cache to initialise. + * @param size The size of the cache. + * @retval true The cache is open. + * @retval false The cache is not open. The RTL error is set. + */ +bool rtems_rtl_obj_cache_open (rtems_rtl_obj_cache_t* cache, size_t size); + +/** + * Close a cache. + * + * @param cache The cache to close. + */ +void rtems_rtl_obj_cache_close (rtems_rtl_obj_cache_t* cache); + +/** + * Flush the cache. Any further read will read the data from the file. + * + * @param cache The cache to flush. + */ +void rtems_rtl_obj_cache_flush (rtems_rtl_obj_cache_t* cache); + +/** + * Read data by reference. The length contains the amount of data that should + * be available in the cache and referenced by the buffer handle. It must be + * less than or equal to the size of the cache. This call will return the + * amount of data that is available. It can be less than you ask if the offset + * and size is past the end of the file. + * + * @param cache The cache to reference data from. + * @param fd The file descriptor. Must be an open file. + * @param offset The offset in the file to reference the data to. + * @param buffer The location to reference the data from. + * @param length The length of data to reference. Can be modified to a + * lesser value and true is still returned so check it. + * @retval true The data referenced is in the cache. + * @retval false The read failed and the RTL error has been set. + */ +bool rtems_rtl_obj_cache_read (rtems_rtl_obj_cache_t* cache, + int fd, + off_t offset, + void** buffer, + size_t* length); + +/** + * Read data by value. The data is copied to the user supplied buffer. + * + * @param cache The cache to read the data from. + * @param fd The file descriptor. Must be an open file. + * @param offset The offset in the file to read the data from. + * @param buffer The location the data is written into. + * @param length The length of data to read. + * @retval true The data has been read from the cache. + * @retval false The read failed and the RTL error has been set. + */ +bool rtems_rtl_obj_cache_read_byval (rtems_rtl_obj_cache_t* cache, + int fd, + off_t offset, + void* buffer, + size_t length); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-obj-comp.c b/cpukit/libdl/rtl-obj-comp.c new file mode 100644 index 0000000000..d9c5462e1e --- /dev/null +++ b/cpukit/libdl/rtl-obj-comp.c @@ -0,0 +1,179 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object Compression manages a compress + * stream of data. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include <rtems/rtl/rtl-allocator.h> +#include "rtl-obj-comp.h" +#include "rtl-error.h" + +#include "fastlz.h" + +#include <stdio.h> + +bool +rtems_rtl_obj_comp_open (rtems_rtl_obj_comp_t* comp, + size_t size) +{ + comp->cache = NULL; + comp->fd = -1; + comp->compression = RTEMS_RTL_COMP_LZ77; + comp->offset = 0; + comp->size = size; + comp->level = 0; + comp->buffer = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, false); + if (!comp->buffer) + { + rtems_rtl_set_error (ENOMEM, "no memory for compressor buffer"); + return false; + } + comp->read = 0; + return true; +} + +void +rtems_rtl_obj_comp_close (rtems_rtl_obj_comp_t* comp) +{ + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, comp->buffer); + comp->cache = NULL; + comp->fd = -1; + comp->compression = RTEMS_RTL_COMP_LZ77; + comp->level = 0; + comp->size = 0; + comp->offset = 0; + comp->read = 0; +} + +void +rtems_rtl_obj_comp_set (rtems_rtl_obj_comp_t* comp, + rtems_rtl_obj_cache_t* cache, + int fd, + int compression, + off_t offset) +{ + comp->cache = cache; + comp->fd = fd; + comp->compression = compression; + comp->offset = offset; + comp->level = 0; + comp->read = 0; +} + +bool +rtems_rtl_obj_comp_read (rtems_rtl_obj_comp_t* comp, + void* buffer, + size_t length) +{ + uint8_t* bin = buffer; + + if (!comp->cache) + { + rtems_rtl_set_error (EINVAL, "not open"); + return false; + } + + if (comp->fd != comp->cache->fd) + { + comp->level = 0; + } + + while (length) + { + size_t buffer_level; + + buffer_level = length > comp->level ? comp->level : length; + + if (buffer_level) + { + memcpy (bin, comp->buffer, buffer_level); + + if ((comp->level - buffer_level) != 0) + { + memmove (comp->buffer, + comp->buffer + buffer_level, + comp->level - buffer_level); + } + + bin += buffer_level; + length -= buffer_level; + comp->level -= buffer_level; + comp->read += buffer_level; + } + + if (length) + { + uint8_t* input = NULL; + uint16_t block_size; + size_t in_length = sizeof (block_size); + int decompressed; + + if (!rtems_rtl_obj_cache_read (comp->cache, comp->fd, comp->offset, + (void**) &input, &in_length)) + return false; + + block_size = (input[0] << 8) | input[1]; + + comp->offset += sizeof (block_size); + + in_length = block_size; + + if (!rtems_rtl_obj_cache_read (comp->cache, comp->fd, comp->offset, + (void**) &input, &in_length)) + return false; + + if (in_length != block_size) + { + rtems_rtl_set_error (EIO, "compressed read failed: bs=%u in=%u", + block_size, in_length); + return false; + } + + switch (comp->compression) + { + case RTEMS_RTL_COMP_NONE: + memcpy (comp->buffer, input, in_length); + decompressed = in_length; + break; + + case RTEMS_RTL_COMP_LZ77: + decompressed = fastlz_decompress (input, in_length, + comp->buffer, comp->size); + if (decompressed == 0) + { + rtems_rtl_set_error (EBADF, "decompression failed"); + return false; + } + break; + + default: + rtems_rtl_set_error (EINVAL, "bad compression type"); + return false; + } + + comp->offset += block_size; + + comp->level = decompressed; + } + } + + return true; +} diff --git a/cpukit/libdl/rtl-obj-comp.h b/cpukit/libdl/rtl-obj-comp.h new file mode 100644 index 0000000000..df7a4299f7 --- /dev/null +++ b/cpukit/libdl/rtl-obj-comp.h @@ -0,0 +1,122 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object File Compression manages a + * compressed stream of data. + * + * This is a simple interface to the object file cache to stream data from + * from a compressed object file. There is no ability to seek with the + * data from a compressed file. The module exists to allocate the output + * buffer when the loader starts and use the cache buffers will have been + * allocated. + */ + +#if !defined (_RTEMS_RTL_OBJ_COMP_H_) +#define _RTEMS_RTL_OBJ_COMP_H_ + +#include <rtems/rtl/rtl-obj-cache.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * The amount of input data read at a time from the file. + */ +#define RTEMS_RTL_DECOMP_INPUT_SIZE (256) + +/** + * The types of supported compression. + */ +#define RTEMS_RTL_COMP_NONE (0) +#define RTEMS_RTL_COMP_LZ77 (1) + +/** + * The compressed file. + */ +typedef struct rtems_rtl_obj_cpmp_s +{ + rtems_rtl_obj_cache_t* cache; /**< The cache provides the input + * buffer. */ + int fd; /**< The file descriptor. */ + int compression; /**< The type of compression. */ + off_t offset; /**< The base offset of the buffer. */ + size_t size; /**< The size of the output buffer. */ + size_t level; /**< The amount of data in the buffer. */ + uint8_t* buffer; /**< The buffer */ + uint32_t read; /**< The amount of data read. */ +} rtems_rtl_obj_comp_t; + +/** + * Return the input level. + */ +static inline uint32_t rtems_rtl_obj_comp_input (rtems_rtl_obj_comp_t* comp) +{ + return comp->read; +} + +/** + * Open a compressor allocating the output buffer. + * + * @param comp The compressor to initialise. + * @param size The size of the compressor's output buffer. + * @retval true The compressor is open. + * @retval false The compressor is not open. The RTL error is set. + */ +bool rtems_rtl_obj_comp_open (rtems_rtl_obj_comp_t* comp, + size_t size); + +/** + * Close a compressor. + * + * @param comp The compressor to close. + */ +void rtems_rtl_obj_comp_close (rtems_rtl_obj_comp_t* comp); + +/** + * Set the cache and offset in the file the compressed stream starts. + * + * @param comp The compressor to set the offset in. + * @param cache The cache to read the file in by. + * @param fd The file descriptor. Must be an open file. + * @param compression The type of compression being streamed. + * @param offset The offset in the file the compressed stream starts. + */ +void rtems_rtl_obj_comp_set (rtems_rtl_obj_comp_t* comp, + rtems_rtl_obj_cache_t* cache, + int fd, + int compression, + off_t offset); + +/** + * Read decompressed data. The length contains the amount of data that should + * be available in the cache and referenced by the buffer handle. It must be + * less than or equal to the size of the cache. This call will return the + * amount of data that is available. It can be less than you ask if the offset + * and size is past the end of the file. + * + * @param comp The compressor to read data from. + * @param buffer The buffer the output is written too. + * @param length The length of data to read. Can be modified to a + * lesser value and true is still returned so check it. + * @retval true The data referenced is in the cache. + * @retval false The read failed and the RTL error has been set. + */ +bool rtems_rtl_obj_comp_read (rtems_rtl_obj_comp_t* comp, + void* buffer, + size_t length); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-obj-fwd.h b/cpukit/libdl/rtl-obj-fwd.h new file mode 100644 index 0000000000..c4186d9a08 --- /dev/null +++ b/cpukit/libdl/rtl-obj-fwd.h @@ -0,0 +1,39 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker ELF Headers + */ + +#if !defined (_RTEMS_RTL_OBJ_FWD_H_) +#define _RTEMS_RTL_OBJ_FWD_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * The forward declaration of the obj section structure. + */ +struct rtems_rtl_obj_sect_s; +typedef struct rtems_rtl_obj_sect_s rtems_rtl_obj_sect_t; + +/** + * The forward declaration of the obj structure. + */ +struct rtems_rtl_obj_s; +typedef struct rtems_rtl_obj_s rtems_rtl_obj_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c new file mode 100644 index 0000000000..d4ee63c035 --- /dev/null +++ b/cpukit/libdl/rtl-obj.c @@ -0,0 +1,1031 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtl + * + * @brief RTEMS Run-Time Linker Error + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> +#include <stdio.h> + +#include <rtems/libio_.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-chain-iterator.h" +#include "rtl-obj.h" +#include "rtl-error.h" +#include "rtl-find-file.h" +#include "rtl-string.h" +#include "rtl-trace.h" + +#if RTEMS_RTL_RAP_LOADER +#include "rtl-rap.h" +#define RTEMS_RTL_RAP_LOADER_COUNT 1 +#else +#define RTEMS_RTL_RAP_LOADER_COUNT 0 +#endif + +#if RTEMS_RTL_ELF_LOADER +#include "rtl-elf.h" +#define RTEMS_RTL_ELF_LOADER_COUNT 1 +#else +#define RTEMS_RTL_ELF_LOADER_COUNT 0 +#endif + +/** + * The table of supported loader formats. + */ +static rtems_rtl_loader_table_t loaders[RTEMS_RTL_ELF_LOADER_COUNT + + RTEMS_RTL_RAP_LOADER_COUNT] = +{ +#if RTEMS_RTL_RAP_LOADER + { rtems_rtl_rap_file_check, rtems_rtl_rap_file_load, rtems_rtl_rap_file_sig }, +#endif +#if RTEMS_RTL_ELF_LOADER + { rtems_rtl_elf_file_check, rtems_rtl_elf_file_load, rtems_rtl_elf_file_sig }, +#endif +}; + +rtems_rtl_obj_t* +rtems_rtl_obj_alloc (void) +{ + rtems_rtl_obj_t* obj = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, + sizeof (rtems_rtl_obj_t), + true); + if (obj) + { + /* + * Initialise the chains. + */ + rtems_chain_initialize_empty (&obj->sections); + } + return obj; +} + +static void +rtems_rtl_obj_free_names (rtems_rtl_obj_t* obj) +{ + if (rtems_rtl_obj_oname_valid (obj)) + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->oname); + if (rtems_rtl_obj_aname_valid (obj)) + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->aname); + if (rtems_rtl_obj_fname_valid (obj)) + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->fname); +} + +bool +rtems_rtl_obj_free (rtems_rtl_obj_t* obj) +{ + if (obj->users || ((obj->flags & RTEMS_RTL_OBJ_LOCKED) != 0)) + { + rtems_rtl_set_error (EINVAL, "cannot free obj still in use"); + return false; + } + if (!rtems_chain_is_node_off_chain (&obj->link)) + rtems_chain_extract (&obj->link); + rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, + &obj->data_base, &obj->bss_base); + rtems_rtl_symbol_obj_erase (obj); + rtems_rtl_obj_free_names (obj); + if (obj->sec_num) + free (obj->sec_num); + if (obj->detail) + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*)obj->detail); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj); + return true; +} + +bool +rtems_rtl_obj_unresolved (rtems_rtl_obj_t* obj) +{ + return (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0 ? true : false; +} + +bool +rtems_rtl_parse_name (const char* name, + const char** aname, + const char** oname, + off_t* ooffset) +{ + const char* laname = NULL; + const char* loname = NULL; + const char* colon; + const char* end; + + /* + * Parse the name to determine if the object file is part of an archive or it + * is an object file. If an archive check the name for a '@' to see if the + * archive contains an offset. + */ + end = name + strlen (name); + colon = strrchr (name, ':'); + if (colon == NULL || colon < strrchr(name, '/')) + colon = end; + + loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, colon - name + 1, true); + if (!oname) + { + rtems_rtl_set_error (ENOMEM, "no memory for object file name"); + return false; + } + + memcpy ((void*) loname, name, colon - name); + + /* + * If the pointers match there is no ':' delimiter. + */ + if (colon != end) + { + const char* at; + + /* + * The file name is an archive and the object file name is next after the + * delimiter. Move the pointer to the archive name. + */ + laname = loname; + ++colon; + + /* + * See if there is a '@' to delimit an archive offset for the object in the + * archive. + */ + at = strchr (colon, '@'); + + if (at == NULL) + at = end; + + + loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, at - colon + 1, true); + if (!loname) + { + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) laname); + rtems_rtl_set_error (ENOMEM, "no memory for object file name"); + return false; + } + + memcpy ((void*) loname, colon, at - colon); + + if (at != end) + { + /* + * The object name has an archive offset. If the number + * does not parse 0 will be returned and the archive will be + * searched. + */ + *ooffset = strtoul (at + 1, 0, 0); + } + } + + *oname = loname; + *aname = laname; + return true; +} + +static bool +rtems_rtl_obj_parse_name (rtems_rtl_obj_t* obj, const char* name) +{ + return rtems_rtl_parse_name (name, &(obj->aname), &(obj->oname), &(obj->ooffset)); +} + +static bool +rtems_rtl_seek_read (int fd, off_t off, size_t len, uint8_t* buffer) +{ + if (lseek (fd, off, SEEK_SET) < 0) + return false; + if (read (fd, buffer, len) != len) + return false; + return true; +} + +/** + * Scan the decimal number returning the value found. + */ +static uint64_t +rtems_rtl_scan_decimal (const uint8_t* string, size_t len) +{ + uint64_t value = 0; + + while (len && (*string != ' ')) + { + value *= 10; + value += *string - '0'; + ++string; + --len; + } + + return value; +} + +/** + * Align the size to the next alignment point. Assume the alignment is a + * positive integral power of 2 if not 0 or 1. If 0 or 1 then there is no + * alignment. + */ +static size_t +rtems_rtl_sect_align (size_t offset, uint32_t alignment) +{ + if ((alignment > 1) && ((offset & ~alignment) != 0)) + offset = (offset + alignment) & ~(alignment - 1); + return offset; +} + +/** + * Section size summer iterator data. + */ +typedef struct +{ + uint32_t mask; /**< The selection mask to sum. */ + size_t size; /**< The size of all section fragments. */ +} rtems_rtl_obj_sect_summer_t; + +static bool +rtems_rtl_obj_sect_summer (rtems_chain_node* node, void* data) +{ + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + rtems_rtl_obj_sect_summer_t* summer = data; + if ((sect->flags & summer->mask) == summer->mask) + summer->size = + rtems_rtl_sect_align (summer->size, sect->alignment) + sect->size; + return true; +} + +static size_t +rtems_rtl_obj_section_size (rtems_rtl_obj_t* obj, uint32_t mask) +{ + rtems_rtl_obj_sect_summer_t summer; + summer.mask = mask; + summer.size = 0; + rtems_rtl_chain_iterate (&obj->sections, + rtems_rtl_obj_sect_summer, + &summer); + return summer.size; +} + +/** + * Section alignment iterator data. The first section's alignment sets the + * alignment for that type of section. + */ +typedef struct +{ + uint32_t mask; /**< The selection mask to look for alignment. */ + uint32_t alignment; /**< The alignment of the section type. */ +} rtems_rtl_obj_sect_aligner_t; + +/** + * The section aligner iterator. + */ +static bool +rtems_rtl_obj_sect_aligner (rtems_chain_node* node, void* data) +{ + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + rtems_rtl_obj_sect_aligner_t* aligner = data; + if ((sect->flags & aligner->mask) == aligner->mask) + { + aligner->alignment = sect->alignment; + return false; + } + return true; +} + +static size_t +rtems_rtl_obj_section_alignment (rtems_rtl_obj_t* obj, uint32_t mask) +{ + rtems_rtl_obj_sect_aligner_t aligner; + aligner.mask = mask; + aligner.alignment = 0; + rtems_rtl_chain_iterate (&obj->sections, + rtems_rtl_obj_sect_aligner, + &aligner); + return aligner.alignment; +} + +static bool +rtems_rtl_obj_section_handler (uint32_t mask, + rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_handler_t handler, + void* data) +{ + rtems_chain_node* node = rtems_chain_first (&obj->sections); + while (!rtems_chain_is_tail (&obj->sections, node)) + { + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + if ((sect->flags & mask) != 0) + { + if (!handler (obj, fd, sect, data)) + return false; + } + node = rtems_chain_next (node); + } + return true; +} + +bool +rtems_rtl_match_name (rtems_rtl_obj_t* obj, const char* name) +{ + const char* n1 = obj->oname; + while ((*n1 != '\0') && (*n1 != '\n') && (*n1 != '/') && + (*name != '\0') && (*name != '/') && (*n1 == *name)) + { + ++n1; + ++name; + } + if (((*n1 == '\0') || (*n1 == '\n') || (*n1 == '/')) && + ((*name == '\0') || (*name == '/'))) + return true; + return false; +} + +bool +rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name) +{ + const char* pname; + rtems_rtl_data_t* rtl; + + /* + * Parse the name. The object descriptor will have the archive name and/or + * object name fields filled in. A find of the file will result in the file + * name (fname) field pointing to the actual file if present on the file + * system. + */ + if (!rtems_rtl_obj_parse_name (obj, name)) + return false; + + /* + * If the archive field (aname) is set we use that name else we use the + * object field (oname). If selected name is absolute we just point the aname + * field to the fname field to that name. If the field is relative we search + * the paths set in the RTL for the file. + */ + if (rtems_rtl_obj_aname_valid (obj)) + pname = rtems_rtl_obj_aname (obj); + else + pname = rtems_rtl_obj_oname (obj); + + rtl = rtems_rtl_lock (); + + if (!rtems_rtl_find_file (pname, rtl->paths, &obj->fname, &obj->fsize)) + { + rtems_rtl_set_error (ENOENT, "file not found"); + rtems_rtl_unlock (); + return false; + } + + rtems_rtl_unlock (); + + return true; +} + +bool +rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj, + int section, + const char* name, + size_t size, + off_t offset, + uint32_t alignment, + int link, + int info, + uint32_t flags) +{ + rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, + sizeof (rtems_rtl_obj_sect_t), true); + if (!sect) + { + rtems_rtl_set_error (ENOMEM, "adding allocated section"); + return false; + } + sect->section = section; + sect->name = rtems_rtl_strdup (name); + sect->size = size; + sect->offset = offset; + sect->alignment = alignment; + sect->link = link; + sect->info = info; + sect->flags = flags; + sect->base = NULL; + rtems_chain_append (&obj->sections, §->node); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION)) + printf ("rtl: sect: %-2d: %s\n", section, name); + + return true; +} + +void +rtems_rtl_obj_erase_sections (rtems_rtl_obj_t* obj) +{ + rtems_chain_node* node = rtems_chain_first (&obj->sections); + while (!rtems_chain_is_tail (&obj->sections, node)) + { + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + rtems_chain_node* next_node = rtems_chain_next (node); + rtems_chain_extract (node); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) sect->name); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, sect); + node = next_node; + } +} + +/** + * Section finder iterator data. + */ +typedef struct +{ + rtems_rtl_obj_sect_t* sect; /**< The matching section. */ + const char* name; /**< The name to match. */ + int index; /**< The index to match. */ +} rtems_rtl_obj_sect_finder_t; + +static bool +rtems_rtl_obj_sect_match_name (rtems_chain_node* node, void* data) +{ + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + rtems_rtl_obj_sect_finder_t* match = data; + if (strcmp (sect->name, match->name) == 0) + { + match->sect = sect; + return false; + } + return true; +} + +rtems_rtl_obj_sect_t* +rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj, const char* name) +{ + rtems_rtl_obj_sect_finder_t match; + match.sect = NULL; + match.name = name; + rtems_rtl_chain_iterate (&obj->sections, + rtems_rtl_obj_sect_match_name, + &match); + return match.sect; +} + +static bool +rtems_rtl_obj_sect_match_index (rtems_chain_node* node, void* data) +{ + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + rtems_rtl_obj_sect_finder_t* match = data; + if (sect->section == match->index) + { + match->sect = sect; + return false; + } + return true; +} + +rtems_rtl_obj_sect_t* +rtems_rtl_obj_find_section_by_index (rtems_rtl_obj_t* obj, int index) +{ + rtems_rtl_obj_sect_finder_t match; + match.sect = NULL; + match.index = index; + rtems_rtl_chain_iterate (&obj->sections, + rtems_rtl_obj_sect_match_index, + &match); + return match.sect; +} + +size_t +rtems_rtl_obj_text_size (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_TEXT); +} + +uint32_t +rtems_rtl_obj_text_alignment (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_TEXT); +} + +size_t +rtems_rtl_obj_const_size (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_CONST); +} + +uint32_t +rtems_rtl_obj_const_alignment (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_CONST); +} + +size_t +rtems_rtl_obj_data_size (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_DATA); +} + +uint32_t +rtems_rtl_obj_data_alignment (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_DATA); +} + +size_t +rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_BSS); +} + +uint32_t +rtems_rtl_obj_bss_alignment (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_BSS); +} + +bool +rtems_rtl_obj_relocate (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_handler_t handler, + void* data) +{ + uint32_t mask = RTEMS_RTL_OBJ_SECT_REL | RTEMS_RTL_OBJ_SECT_RELA; + return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data); +} + +bool +rtems_rtl_obj_load_symbols (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_handler_t handler, + void* data) +{ + uint32_t mask = RTEMS_RTL_OBJ_SECT_SYM; + return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data); +} + +static size_t +rtems_rtl_obj_sections_loader (uint32_t mask, + rtems_rtl_obj_t* obj, + int fd, + uint8_t* base, + rtems_rtl_obj_sect_handler_t handler, + void* data) +{ + rtems_chain_control* sections = &obj->sections; + rtems_chain_node* node = rtems_chain_first (sections); + size_t base_offset = 0; + bool first = true; + while (!rtems_chain_is_tail (sections, node)) + { + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + + if ((sect->size != 0) && ((sect->flags & mask) != 0)) + { + if (!first) + base_offset = rtems_rtl_sect_align (base_offset, sect->alignment); + + sect->base = base + base_offset; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT)) + printf ("rtl: loading: %s -> %8p (%zi)\n", + sect->name, sect->base, sect->size); + + if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD) + { + if (!handler (obj, fd, sect, data)) + { + sect->base = 0; + return false; + } + } + else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO) + { + memset (base + base_offset, 0, sect->size); + } + else + { + sect->base = 0; + rtems_rtl_set_error (errno, "section has no load op"); + return false; + } + + base_offset += sect->size; + first = false; + } + + node = rtems_chain_next (node); + } + + return true; +} + +bool +rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_handler_t handler, + void* data) +{ + size_t text_size; + size_t const_size; + size_t data_size; + size_t bss_size; + + text_size = rtems_rtl_obj_text_size (obj) + rtems_rtl_obj_const_alignment (obj); + const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_data_alignment (obj); + data_size = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj); + bss_size = rtems_rtl_obj_bss_size (obj); + + /* + * Let the allocator manage the actual allocation. The user can use the + * standard heap or provide a specific allocator with memory protection. + */ + if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size, + &obj->const_base, const_size, + &obj->data_base, data_size, + &obj->bss_base, bss_size)) + { + obj->exec_size = 0; + rtems_rtl_set_error (ENOMEM, "no memory to load obj"); + return false; + } + + obj->exec_size = text_size + const_size + data_size + bss_size; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT)) + { + printf ("rtl: load sect: text - b:%p s:%zi a:%" PRIu32 "\n", + obj->text_base, text_size, rtems_rtl_obj_text_alignment (obj)); + printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n", + obj->const_base, const_size, rtems_rtl_obj_const_alignment (obj)); + printf ("rtl: load sect: data - b:%p s:%zi a:%" PRIu32 "\n", + obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj)); + printf ("rtl: load sect: bss - b:%p s:%zi a:%" PRIu32 "\n", + obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj)); + } + + /* + * Load all text then data then bss sections in seperate operations so each + * type of section is grouped together. + */ + if (!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_TEXT, + obj, fd, obj->text_base, handler, data) || + !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST, + obj, fd, obj->const_base, handler, data) || + !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_DATA, + obj, fd, obj->data_base, handler, data) || + !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS, + obj, fd, obj->bss_base, handler, data)) + { + rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, + &obj->data_base, &obj->bss_base); + obj->exec_size = 0; + return false; + } + + return true; +} + +static void +rtems_rtl_obj_run_cdtors (rtems_rtl_obj_t* obj, uint32_t mask) +{ + rtems_chain_node* node = rtems_chain_first (&obj->sections); + while (!rtems_chain_is_tail (&obj->sections, node)) + { + rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; + if ((sect->flags & mask) == mask) + { + rtems_rtl_cdtor_t* handler; + size_t handlers = sect->size / sizeof (rtems_rtl_cdtor_t); + int c; + for (c = 0, handler = sect->base; c < handlers; ++c) + if (*handler) + (*handler) (); + } + node = rtems_chain_next (node); + } +} + +void +rtems_rtl_obj_run_ctors (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_CTOR); +} + +void +rtems_rtl_obj_run_dtors (rtems_rtl_obj_t* obj) +{ + return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_DTOR); +} + +/** + * Find a module in an archive returning the offset in the archive in the + * object descriptor. + */ +static bool +rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd) +{ +#define RTEMS_RTL_AR_IDENT "!<arch>\n" +#define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1) +#define RTEMS_RTL_AR_FHDR_BASE RTEMS_RTL_AR_IDENT_SIZE +#define RTEMS_RTL_AR_FNAME (0) +#define RTEMS_RTL_AR_FNAME_SIZE (16) +#define RTEMS_RTL_AR_SIZE (48) +#define RTEMS_RTL_AR_SIZE_SIZE (10) +#define RTEMS_RTL_AR_MAGIC (58) +#define RTEMS_RTL_AR_MAGIC_SIZE (2) +#define RTEMS_RTL_AR_FHDR_SIZE (60) + + size_t fsize = obj->fsize; + off_t extended_file_names; + uint8_t header[RTEMS_RTL_AR_FHDR_SIZE]; + bool scanning; + + if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) != RTEMS_RTL_AR_IDENT_SIZE) + { + rtems_rtl_set_error (errno, "reading archive identifer"); + return false; + } + + if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0) + { + rtems_rtl_set_error (EINVAL, "invalid archive identifer"); + return false; + } + + /* + * Seek to the current offset in the archive and if we have a valid archive + * file header present check the file name for a match with the oname field + * of the object descriptor. If the archive header is not valid and it is the + * first pass reset the offset and start the search again in case the offset + * provided is not valid any more. + * + * The archive can have a symbol table at the start. Ignore it. A symbol + * table has the file name '/'. + * + * The archive can also have the GNU extended file name table. This + * complicates the processing. If the object's file name starts with '/' the + * remainder of the file name is an offset into the extended file name + * table. To find the extended file name table we need to scan from start of + * the archive for a file name of '//'. Once found we remeber the table's + * start and can direct seek to file name location. In other words the scan + * only happens once. + * + * If the name had the offset encoded we go straight to that location. + */ + + if (obj->ooffset != 0) + scanning = false; + else + { + scanning = true; + obj->ooffset = RTEMS_RTL_AR_FHDR_BASE; + } + + extended_file_names = 0; + + while (obj->ooffset < fsize) + { + /* + * Clean up any existing data. + */ + memset (header, 0, sizeof (header)); + + if (!rtems_rtl_seek_read (fd, obj->ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0])) + { + rtems_rtl_set_error (errno, "seek/read archive file header"); + obj->ooffset = 0; + obj->fsize = 0; + return false; + } + + if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) || + (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a)) + { + if (scanning) + { + rtems_rtl_set_error (EINVAL, "invalid archive file header"); + obj->ooffset = 0; + obj->fsize = 0; + return false; + } + + scanning = true; + obj->ooffset = RTEMS_RTL_AR_FHDR_BASE; + continue; + } + + /* + * The archive header is always aligned to an even address. + */ + obj->fsize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE], + RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1; + + /* + * Check for the GNU extensions. + */ + if (header[0] == '/') + { + off_t extended_off; + + switch (header[1]) + { + case ' ': + /* + * Symbols table. Ignore the table. + */ + break; + case '/': + /* + * Extended file names table. Remember. + */ + extended_file_names = obj->ooffset + RTEMS_RTL_AR_FHDR_SIZE; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* + * Offset into the extended file name table. If we do not have the + * offset to the extended file name table find it. + */ + extended_off = + rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE); + + if (extended_file_names == 0) + { + off_t off = obj->ooffset; + while (extended_file_names == 0) + { + off_t esize = + (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE], + RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1; + off += esize + RTEMS_RTL_AR_FHDR_SIZE; + + if (!rtems_rtl_seek_read (fd, off, + RTEMS_RTL_AR_FHDR_SIZE, &header[0])) + { + rtems_rtl_set_error (errno, + "seeking/reading archive ext file name header"); + obj->ooffset = 0; + obj->fsize = 0; + return false; + } + + if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) || + (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a)) + { + rtems_rtl_set_error (errno, "invalid archive file header"); + obj->ooffset = 0; + obj->fsize = 0; + return false; + } + + if ((header[0] == '/') && (header[1] == '/')) + { + extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE; + break; + } + } + } + + if (extended_file_names) + { + /* + * We know the offset in the archive to the extended file. Read the + * name from the table and compare with the name we are after. + */ +#define RTEMS_RTL_MAX_FILE_SIZE (256) + char name[RTEMS_RTL_MAX_FILE_SIZE]; + + if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off, + RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0])) + { + rtems_rtl_set_error (errno, + "invalid archive ext file seek/read"); + obj->ooffset = 0; + obj->fsize = 0; + return false; + } + + if (rtems_rtl_match_name (obj, name)) + { + obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE; + return true; + } + } + break; + default: + /* + * Ignore the file because we do not know what it it. + */ + break; + } + } + else + { + if (rtems_rtl_match_name (obj, (const char*) &header[RTEMS_RTL_AR_FNAME])) + { + obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE; + return true; + } + } + + obj->ooffset += obj->fsize + RTEMS_RTL_AR_FHDR_SIZE; + } + + rtems_rtl_set_error (ENOENT, "object file not found"); + obj->ooffset = 0; + obj->fsize = 0; + return false; +} + +bool +rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd) +{ + int l; + + for (l = 0; l < (sizeof (loaders) / sizeof (rtems_rtl_loader_table_t)); ++l) + { + if (loaders[l].check (obj, fd)) + return loaders[l].load (obj, fd); + } + + rtems_rtl_set_error (ENOENT, "no format loader found"); + return false; +} + +bool +rtems_rtl_obj_load (rtems_rtl_obj_t* obj) +{ + int fd; + + if (!rtems_rtl_obj_fname_valid (obj)) + { + rtems_rtl_set_error (ENOMEM, "invalid object file name path"); + return false; + } + + fd = open (rtems_rtl_obj_fname (obj), O_RDONLY); + if (fd < 0) + { + rtems_rtl_set_error (ENOMEM, "opening for object file"); + return false; + } + + /* + * Find the object file in the archive if it is an archive that + * has been opened. + */ + if (rtems_rtl_obj_aname_valid (obj)) + { + if (!rtems_rtl_obj_archive_find (obj, fd)) + { + rtems_rtl_obj_caches_flush (); + close (fd); + return false; + } + } + + /* + * Call the format specific loader. Currently this is a call to the ELF + * loader. This call could be changed to allow probes then calls if more than + * one format is supported. + */ + if (!rtems_rtl_obj_file_load (obj, fd)) + { + rtems_rtl_obj_caches_flush (); + close (fd); + return false; + } + + if (!_rtld_linkmap_add (obj)) /* For GDB */ + { + close (fd); + return false; + } + + rtems_rtl_obj_caches_flush (); + + close (fd); + + return true; +} + +bool +rtems_rtl_obj_unload (rtems_rtl_obj_t* obj) +{ + _rtld_linkmap_delete(obj); + rtems_rtl_symbol_obj_erase (obj); + return rtems_rtl_obj_free (obj); +} diff --git a/cpukit/libdl/rtl-obj.h b/cpukit/libdl/rtl-obj.h new file mode 100644 index 0000000000..05507232ca --- /dev/null +++ b/cpukit/libdl/rtl-obj.h @@ -0,0 +1,580 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object Support. + */ + +#if !defined (_RTEMS_RTL_OBJ_H_) +#define _RTEMS_RTL_OBJ_H_ + +#include <rtems.h> +#include <rtems/chain.h> +#include <rtems/rtl/rtl-sym.h> +#include <rtems/rtl/rtl-unresolved.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Loader format flags. + */ +#define RTEMS_RTL_FMT_ELF (1 << 0) +#define RTEMS_RTL_FMT_COMP (1 << 1) +#define RTEMS_RTL_FMT_PRIVATE (1 << 16) + +/** + * Loader format definition. + */ +typedef struct rtems_rtl_loader_format_s +{ + /** + * The format label. This can be used to determine and manage + * specific formats. + */ + const char* label; + + /** + * The format flags. + */ + uint32_t flags; +} rtems_rtl_loader_format_t; + +/** + * The type of the format loader check handler. This handler checks the format + * and if it is detected as suitable it returns true. + */ +typedef bool (*rtems_rtl_loader_check) (rtems_rtl_obj_t* obj, int fd); + +/** + * The type of the format loader handler. This handler loads the specific + * format. + */ +typedef bool (*rtems_rtl_loader_load) (rtems_rtl_obj_t* obj, int fd); + +/** + * The type of the format loader handler. This handler loads the specific + * format. + */ +typedef rtems_rtl_loader_format_t* (*rtems_rtl_loader_sig) (void); + +/** + * Table for supported loadable formats. + */ +typedef struct rtems_rtl_loader_table_s +{ + rtems_rtl_loader_check check; /**< The check handler. */ + rtems_rtl_loader_load load; /**< The loader. */ + rtems_rtl_loader_sig signature; /**< The loader's signature. */ +} rtems_rtl_loader_table_t; + +/** + * Flags for the various section types. + */ +#define RTEMS_RTL_OBJ_SECT_TEXT (1 << 0) /**< Section holds program text. */ +#define RTEMS_RTL_OBJ_SECT_CONST (1 << 1) /**< Section holds program text. */ +#define RTEMS_RTL_OBJ_SECT_DATA (1 << 2) /**< Section holds program data. */ +#define RTEMS_RTL_OBJ_SECT_BSS (1 << 3) /**< Section holds program bss. */ +#define RTEMS_RTL_OBJ_SECT_REL (1 << 4) /**< Section holds relocation records. */ +#define RTEMS_RTL_OBJ_SECT_RELA (1 << 5) /**< Section holds relocation addend + * records. */ +#define RTEMS_RTL_OBJ_SECT_SYM (1 << 6) /**< Section holds symbols. */ +#define RTEMS_RTL_OBJ_SECT_STR (1 << 7) /**< Section holds strings. */ +#define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 8) /**< Section allocates runtime memory. */ +#define RTEMS_RTL_OBJ_SECT_LOAD (1 << 9) /**< Section is loaded from object file. */ +#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 10) /**< Section is writable, ie data. */ +#define RTEMS_RTL_OBJ_SECT_EXEC (1 << 11) /**< Section is executable. */ +#define RTEMS_RTL_OBJ_SECT_ZERO (1 << 12) /**< Section is preset to zero. */ +#define RTEMS_RTL_OBJ_SECT_CTOR (1 << 13) /**< Section contains constructors. */ +#define RTEMS_RTL_OBJ_SECT_DTOR (1 << 14) /**< Section contains destructors. */ + +/** + * An object file is made up of sections and the can be more than + * one of a specific type of sections. All sections and grouped + * together in memory. + */ +struct rtems_rtl_obj_sect_s +{ + rtems_chain_node node; /**< The node's link in the chain. */ + int section; /**< The section number. */ + const char* name; /**< The section's name. */ + size_t size; /**< The size of the section in memory. */ + off_t offset; /**< Offset into the object file. Relative to + * the start of the object file. */ + uint32_t alignment; /**< Alignment of this section. */ + int link; /**< Section link field. */ + int info; /**< Secfion info field. */ + uint32_t flags; /**< The section's flags. */ + void* base; /**< The base address of the section in + * memory. */ +}; + +/** + * Object file descriptor flags. + */ +#define RTEMS_RTL_OBJ_LOCKED (1 << 0) /**< Lock the object file so it cannot + * be unloaded. */ +#define RTEMS_RTL_OBJ_UNRESOLVED (1 << 1) /**< The object file has unresolved + * external symbols. */ + +/** + * RTL Object. There is one for each object module loaded plus one for the base + * kernel image. + */ +struct rtems_rtl_obj_s +{ + rtems_chain_node link; /**< The node's link in the chain. */ + uint32_t flags; /**< The status of the object file. */ + uint32_t users; /**< References to the object file. */ + const char* fname; /**< The file name for the object. */ + const char* oname; /**< The object file name. Can be + * relative. */ + const char* aname; /**< The archive name containing the + * object. NULL means the object is not + * in a lib */ + off_t ooffset; /**< The object offset in the archive. */ + size_t fsize; /**< Size of the object file. */ + rtems_chain_control sections; /**< The sections of interest in the + * object file. */ + rtems_rtl_obj_sym_t* global_table; /**< Global symbol table. */ + size_t global_syms; /**< Global symbol count. */ + size_t global_size; /**< Global symbol memory usage. */ + uint32_t unresolved; /**< The number of unresolved relocations. */ + void* text_base; /**< The base address of the text section + * in memory. */ + void* const_base; /**< The base address of the const section + * in memory. */ + void* data_base; /**< The base address of the data section + * in memory. */ + void* bss_base; /**< The base address of the bss section + * in memory. */ + size_t bss_size; /**< The size of the bss section. */ + size_t exec_size; /**< The amount of executable memory + * allocated */ + void* entry; /**< The entry point of the module. */ + uint32_t checksum; /**< The checksum of the text sections. A + * zero means do not checksum. */ + void* detail; /**< The file details. It contains the elf file + * detail, mainly including elf file name, + * section offset, section size, which + * elf this section belongs to.*/ + uint32_t* sec_num; /**< The sec nums of each obj. */ + uint32_t obj_num; /**< The count of elf files in an rtl obj. */ + struct link_map* linkmap; /**< For GDB. */ +}; + +/** + * A section handler is called once for each section that needs to be + * processed by this handler. + * + * @param obj The object file's descriptor the section belongs too. + * @param fd The file descriptor of the object file beling loaded. + * @param sect The section the handler is being invoked to handle. + * @param data A user supplied data variable. + * @retval true The operation was successful. + * @retval false The operation failed and the RTL has been set. + */ +typedef bool (*rtems_rtl_obj_sect_handler_t)(rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_t* sect, + void* data); + +/** + * Get the file name. + * + * @param obj The object file. + * @return const char* The string. + */ +static inline const char* rtems_rtl_obj_fname (const rtems_rtl_obj_t* obj) +{ + return obj->fname; +} + +/** + * Is the file name valid ? + * + * @param obj The object file. + * @return bool There is a file name + */ +static inline bool rtems_rtl_obj_fname_valid (const rtems_rtl_obj_t* obj) +{ + return obj->fname; +} + +/** + * Get the object name. + * + * @param obj The object file. + * @return const char* The string. + */ +static inline const char* rtems_rtl_obj_oname (const rtems_rtl_obj_t* obj) +{ + return obj->oname; +} + +/** + * Is the object name valid ? + * + * @param obj The object file. + * @return bool There is an object name + */ +static inline bool rtems_rtl_obj_oname_valid (const rtems_rtl_obj_t* obj) +{ + return obj->oname; +} + +/** + * Get the archive name. + * + * @param obj The object file. + * @return const char* The string. + */ +static inline const char* rtems_rtl_obj_aname (const rtems_rtl_obj_t* obj) +{ + return obj->aname; +} + +/** + * Is the archive name valid ? + * + * @param obj The object file. + * @return bool There is an archive name + */ +static inline bool rtems_rtl_obj_aname_valid (const rtems_rtl_obj_t* obj) +{ + return obj->aname; +} + +/** + * Allocate an object structure on the heap. + * + * @retval NULL No memory for the object. + */ +rtems_rtl_obj_t* rtems_rtl_obj_alloc (void); + +/** + * Free the object structure and related resources. + * + * @param obj The object file's descriptor to free. + * @retval false The object has dependences. + * @retval true The object has been freed. + */ +bool rtems_rtl_obj_free (rtems_rtl_obj_t* obj); + +/** + * Does the object file have unresolved external references ? If it does the + * results of executing code is unpredictable. + * + * @param obj The object file's descriptor. + * @retval true The object file has unresolved externals. + * @retval false The object file has all external references resolved. + */ +bool rtems_rtl_obj_unresolved (rtems_rtl_obj_t* obj); + +/** + * Parses a filename and returns newly allocated strings with the archive name, + * object name, and the object's offset + * + * @param name The filename of the object + * @param aname Address of a string pointer that holds the archive name + * @param oname Address of a string pointer that holds the object name + * @param ooffset Address of an int that holds the object offset + * @retval true The parsing was successful + * @retval false The parsing was unsuccessful + */ +bool rtems_rtl_parse_name (const char* name, + const char** aname, + const char** oname, + off_t* ooffset); + +/** + * Load the object file. + * + * @param obj The object file's descriptor. + * @param fd The file descriptor. + * @param load_syms Load symbols. + * @param load_dep Load dependent object files. + * @retval true The load was successful. + * @retval false The load failed. The RTL error has been set. + */ +bool rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd); + +/** + * Check of the name matches the object file's object name. + * + * @param obj The object file's descriptor. + * @param name The name to match. + */ +bool rtems_rtl_match_name (rtems_rtl_obj_t* obj, const char* name); + +/** + * Find an object file on disk that matches the name. The object descriptor is + * fill in with the various parts of a name. A name can have archive, object + * file and offset components. The search path in the RTL is searched. + * + * @param obj The object file's descriptor. + * @param name The name to locate on disk. + * @retval true The file has been found. + * @retval false The file could not be located. The RTL error has been set. + */ +bool rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name); + +/** + * Add a section to the object descriptor. + * + * @param obj The object file's descriptor. + * @param section The section's index number. + * @param name The name of the section. + * @param size The size of the section in memory. + * @param offset The offset of the section in the object file. + * @param alignment The alignment of the section in memory. + * @param link The section's link field (from the ELF format). + * @param info The section's info field (from the ELF format). + * @param flags The section's flags. + * @retval true The section has been added. + * @retval false The section has not been added. See the RTL error. + */ +bool rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj, + int section, + const char* name, + size_t size, + off_t offset, + uint32_t alignment, + int link, + int info, + uint32_t flags); + +/** + * Erase the object file descriptor's sections. + * + * @param obj The object file's descriptor. + */ +void rtems_rtl_obj_erase_sections (rtems_rtl_obj_t* obj); + +/** + * Find the section given a name. + * + * @param obj The object file's descriptor. + * @param name The name of the section to find. + * @retval NULL The section was not found. + * @return rtems_rtl_obj_sect_t* The named section. + */ +rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj, + const char* name); + +/** + * Find a section given a section's index number. + * + * @param obj The object file's descriptor. + * @param index The section's index to find. + * @retval NULL The section was not found. + * @return rtems_rtl_obj_sect_t* The found section. + */ +rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section_by_index (rtems_rtl_obj_t* obj, + int index); + +/** + * The text size of the object file. Only use once all the sections has been + * added. It includes alignments between sections that are part of the object's + * text area. The consts sections are included in this section. + * + * @param obj The object file's descriptor. + * @return size_t The size of the text area of the object file. + */ +size_t rtems_rtl_obj_text_size (rtems_rtl_obj_t* obj); + +/** + * The text section alignment of the object file. Only use once all the + * sections has been added. The section alignment is the alignment of the first + * text type section loaded the text section. + * + * You can assume the alignment is a positive integral power of 2 if not 0 or + * 1. If 0 or 1 then there is no alignment. + * + * @param obj The object file's descriptor. + * @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment. + */ +uint32_t rtems_rtl_obj_text_alignment (rtems_rtl_obj_t* obj); + +/** + * The const size of the object file. Only use once all the sections has been + * added. It includes alignments between sections that are part of the object's + * const area. The consts sections are included in this section. + * + * @param obj The object file's descriptor. + * @return size_t The size of the const area of the object file. + */ +size_t rtems_rtl_obj_const_size (rtems_rtl_obj_t* obj); + +/** + * The const section alignment of the object file. Only use once all the + * sections has been added. The section alignment is the alignment of the first + * const type section loaded the const section. + * + * You can assume the alignment is a positive integral power of 2 if not 0 or + * 1. If 0 or 1 then there is no alignment. + * + * @param obj The object file's descriptor. + * @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment. + */ +uint32_t rtems_rtl_obj_const_alignment (rtems_rtl_obj_t* obj); + +/** + * The data size of the object file. Only use once all the sections has been + * added. It includes alignments between sections that are part of the object's + * data area. + * + * @param obj The object file's descriptor. + * @return size_t The size of the data area of the object file. + */ +size_t rtems_rtl_obj_data_size (rtems_rtl_obj_t* obj); + +/** + * The data section alignment of the object file. Only use once all the + * sections has been added. The section alignment is the alignment of the first + * data type section loaded the data section. + * + * You can assume the alignment is a positive integral power of 2 if not 0 or + * 1. If 0 or 1 then there is no alignment. + * + * @param obj The object file's descriptor. + * @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment. + */ +uint32_t rtems_rtl_obj_data_alignment (rtems_rtl_obj_t* obj); + +/** + * The bss size of the object file. Only use once all the sections has been + * added. It includes alignments between sections that are part of the object's + * bss area. + * + * @param obj The object file's descriptor. + * @return size_t The size of the bss area of the object file. + */ +size_t rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj); + +/** + * The bss section alignment of the object file. Only use once all the + * sections has been added. The section alignment is the alignment of the first + * bss type section loaded the bss section. + * + * You can assume the alignment is a positive integral power of 2 if not 0 or + * 1. If 0 or 1 then there is no alignment. + * + * @param obj The object file's descriptor. + * @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment. + */ +uint32_t rtems_rtl_obj_bss_alignment (rtems_rtl_obj_t* obj); + +/** + * Relocate the object file. The object file's section are parsed for any + * relocation type sections. + * + * @param obj The object file's descriptor. + * @param fd The object file's file descriptor. + * @param handler The object file's format specific relocation handler. + * @param data User specific data handle. + * @retval true The object file was relocated. + * @retval false The relocation failed. The RTL error is set. + */ +bool rtems_rtl_obj_relocate (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_handler_t handler, + void* data); + +/** + * Relocate an object file's unresolved reference. + * + * @param rec The unresolved relocation record. + * @param sym The unresolved relocation's referenced symbol. + * @retval true The object file record was relocated. + * @retval false The relocation failed. The RTL error is set. + */ +bool rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc_t* reloc, + rtems_rtl_obj_sym_t* sym); + +/** + * Load the symbols from the object file. Only the exported or public symbols + * are read into memory and held in the global symbol table. + * + * @param obj The object file's descriptor. + * @param fd The object file's file descriptor. + * @param handler The object file's format specific symbol handler. + * @param data User specific data handle. + * @retval true The object file's symbol where loaded. + * @retval false The symbol loading failed. The RTL error is set. + */ +bool rtems_rtl_obj_load_symbols (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_handler_t handler, + void* data); + +/** + * Load the sections that have been allocated memory in the target. The bss + * type section does not load any data, it is set to 0. The text and data + * sections read the detault data from the object file into the target memory. + * + * @param obj The object file's descriptor. + * @param fd The object file's file descriptor. + * @param handler The object file's format specific load handler. + * @param data User specific data handle. + * @retval true The object has been sucessfully loaded. + * @retval false The load failed. The RTL error has been set. + */ +bool rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_handler_t handler, + void* data); + +/** + * Invoke the constructors the object has. Constructors are a table of pointers + * to "void (*)(void);" where NULL pointers are skipped. The table's size is + * taken from the section's size. The objet ELF specific code is responisble + * for flagging which sections contain constructors. + * + * @param obj The object file's descriptor. + */ +void rtems_rtl_obj_run_ctors (rtems_rtl_obj_t* obj); + +/** + * Invoke the destructors the object has. Destructors are a table of pointers + * to "void (*)(void);" where NULL pointers are skipped. The table's size is + * taken from the section's size. The objet ELF specific code is responisble + * for flagging which sections contain destructors. + * + * @param obj The object file's descriptor. + */ +void rtems_rtl_obj_run_dtors (rtems_rtl_obj_t* obj); + +/** + * Load the object file, reading all sections into memory, symbols and + * performing any relocation fixups. + * + * @param obj The object file's descriptor. + * @retval true The object file has been loaded. + * @retval false The load failed. The RTL error has been set. + */ +bool rtems_rtl_obj_load (rtems_rtl_obj_t* obj); + +/** + * Unload the object file, erasing all symbols and releasing all memory. + * + * @param obj The object file's descriptor. + * @retval true The object file has been unloaded. + * @retval false The unload failed. The RTL error has been set. + */ +bool rtems_rtl_obj_unload (rtems_rtl_obj_t* obj); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-rap.c b/cpukit/libdl/rtl-rap.c new file mode 100644 index 0000000000..ad05b245eb --- /dev/null +++ b/cpukit/libdl/rtl-rap.c @@ -0,0 +1,980 @@ +/* + * COPYRIGHT (c) 2012-2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor + * + * This is the RAP format loader support.. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-obj-comp.h" +#include "rtl-rap.h" +#include "rtl-trace.h" +#include "rtl-unresolved.h" + +/** + * The offsets in the unresolved array. + */ +#define REL_R_OFFSET (0) +#define REL_R_INFO (1) +#define REL_R_ADDEND (2) + +/** + * The ELF format signature. + */ +static rtems_rtl_loader_format_t rap_sig = +{ + .label = "RAP", + .flags = RTEMS_RTL_FMT_COMP +}; + +/** + * The section definitions found in a RAP file. + */ +typedef struct rtems_rtl_rap_sectdef_s +{ + const char* name; /**< Name of the section. */ + const uint32_t flags; /**< Section flags. */ +} rtems_rtl_rap_sectdef_t; + +/** + * The section indexes. These are fixed. + */ +#define RTEMS_RTL_RAP_TEXT_SEC (0) +#define RTEMS_RTL_RAP_CONST_SEC (1) +#define RTEMS_RTL_RAP_CTOR_SEC (2) +#define RTEMS_RTL_RAP_DTOR_SEC (3) +#define RTEMS_RTL_RAP_DATA_SEC (4) +#define RTEMS_RTL_RAP_BSS_SEC (5) +#define RTEMS_RTL_RAP_SECS (6) + +/** + * The sections as loaded from a RAP file. + */ +static const rtems_rtl_rap_sectdef_t rap_sections[RTEMS_RTL_RAP_SECS] = +{ + { ".text", RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD }, + { ".const", RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD }, + { ".ctor", RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_CTOR }, + { ".dtor", RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_DTOR }, + { ".data", RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD }, + { ".bss", RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO } +}; + +/** + * The section definitions found in a RAP file. + */ +typedef struct rtems_rtl_rap_section_s +{ + uint32_t size; /**< The size of the section. */ + uint32_t alignment; /**< The alignment of the section. */ +} rtems_rtl_rap_section_t; + +/** + * The RAP loader. + */ +typedef struct rtems_rtl_rap_s +{ + rtems_rtl_obj_cache_t* file; /**< The file cache for the RAP file. */ + rtems_rtl_obj_comp_t* decomp; /**< The decompression streamer. */ + uint32_t length; /**< The file length. */ + uint32_t version; /**< The RAP file version. */ + uint32_t compression; /**< The type of compression. */ + uint32_t checksum; /**< The checksum. */ + uint32_t machinetype; /**< The ELF machine type. */ + uint32_t datatype; /**< The ELF data type. */ + uint32_t class; /**< The ELF class. */ + uint32_t init; /**< The initialisation strtab offset. */ + uint32_t fini; /**< The finish strtab offset. */ + rtems_rtl_rap_section_t secs[RTEMS_RTL_RAP_SECS]; /**< The sections. */ + uint32_t symtab_size; /**< The symbol table size. */ + char* strtab; /**< The string table. */ + uint32_t strtab_size; /**< The string table size. */ + uint32_t relocs_size; /**< The relocation table size. */ + uint32_t symbols; /**< The number of symbols. */ + uint32_t strtable_size;/**< The size of section names and obj names. */ + uint32_t rpathlen; /**< The length of rpath. */ + char* strtable; /**< The detail string which resides in obj detail. */ +} rtems_rtl_rap_t; + +/** + * Check the machine type. + */ +static bool +rtems_rtl_rap_machine_check (uint32_t machinetype) +{ + /* + * This code is determined by the machine headers. + */ + switch (machinetype) + { + ELFDEFNNAME (MACHDEP_ID_CASES) + default: + return false; + } + return true; +} + +/** + * Check the data type. + */ +static bool +rtems_rtl_rap_datatype_check (uint32_t datatype) +{ + /* + * This code is determined by the machine headers. + */ + if (datatype != ELFDEFNNAME (MACHDEP_ENDIANNESS)) + return false; + return true; +} + +/** + * Check the class of executable. + */ +static bool +rtems_rtl_rap_class_check (uint32_t class) +{ + /* + * This code is determined by the machine headers. + */ + switch (class) + { + case ELFCLASS32: + if (ARCH_ELFSIZE == 32) + return true; + break; + case ELFCLASS64: + if (ARCH_ELFSIZE == 64) + return true; + break; + default: + break; + } + return false; +} + +static uint32_t +rtems_rtl_rap_get_uint32 (const uint8_t* buffer) +{ + uint32_t value = 0; + int b; + for (b = 0; b < sizeof (uint32_t); ++b) + { + value <<= 8; + value |= buffer[b]; + } + return value; +} + +static bool +rtems_rtl_rap_read_uint32 (rtems_rtl_obj_comp_t* comp, uint32_t* value) +{ + uint8_t buffer[sizeof (uint32_t)]; + + if (!rtems_rtl_obj_comp_read (comp, buffer, sizeof (uint32_t))) + return false; + + *value = rtems_rtl_rap_get_uint32 (buffer); + + return true; +} + +static bool +rtems_rtl_rap_loader (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_t* sect, + void* data) +{ + rtems_rtl_rap_t* rap = (rtems_rtl_rap_t*) data; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input %s=%lu\n", + sect->name, rtems_rtl_obj_comp_input (rap->decomp)); + + return rtems_rtl_obj_comp_read (rap->decomp, sect->base, sect->size); +} + +static bool +rtems_rtl_rap_relocate (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) +{ + #define SYMNAME_BUFFER_SIZE (1024) + char* symname_buffer = NULL; + int section; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: relocation\n"); + + symname_buffer = malloc (SYMNAME_BUFFER_SIZE); + if (!symname_buffer) + { + rtems_rtl_set_error (ENOMEM, "no memory for local symbol name buffer"); + return false; + } + + for (section = 0; section < RTEMS_RTL_RAP_SECS; ++section) + { + rtems_rtl_obj_sect_t* targetsect; + uint32_t header = 0; + int relocs; + bool is_rela; + int r; + + targetsect = rtems_rtl_obj_find_section (obj, rap_sections[section].name); + + if (!targetsect) + { + rtems_rtl_set_error (EINVAL, "no target section found"); + free (symname_buffer); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &header)) + { + free (symname_buffer); + return false; + } + + /* + * Bit 31 of the header indicates if the relocations for this section + * have a valid addend field. + */ + + is_rela = (header & (1 << 31)) != 0 ? true : false; + relocs = header & ~(1 << 31); + + if (relocs && rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: relocation: %s: header: %08lx relocs: %d %s\n", + rap_sections[section].name, + header, relocs, is_rela ? "rela" : "rel"); + + for (r = 0; r < relocs; ++r) + { + uint32_t info = 0; + uint32_t offset = 0; + uint32_t addend = 0; + Elf_Word type; + const char* symname = NULL; + uint32_t symname_size; + Elf_Word symtype = 0; + Elf_Word symvalue = 0; + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &info)) + { + free (symname_buffer); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &offset)) + { + free (symname_buffer); + return false; + } + + /* + * The types are: + * + * 0 Section symbol offset in addend. + * 1 Symbol appended to the relocation record. + * 2 Symbol is in the strtabl. + * + * If type 2 bits 30:8 is the offset in the strtab. If type 1 the bits + * are the size of the string. The lower 8 bits of the info field if the + * ELF relocation type field. + */ + + if (((info & (1 << 31)) == 0) || is_rela) + { + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &addend)) + { + free (symname_buffer); + return false; + } + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf (" %2d: info=%08lx offset=%lu addend=%lu\n", + r, info, offset, addend); + + type = info & 0xff; + + if ((info & (1 << 31)) == 0) + { + rtems_rtl_obj_sect_t* symsect; + + symsect = rtems_rtl_obj_find_section_by_index (obj, info >> 8); + if (!symsect) + { + free (symname_buffer); + return false; + } + + symvalue = (Elf_Word) symsect->base + addend; + } + else if (rtems_rtl_elf_rel_resolve_sym (type)) + { + rtems_rtl_obj_sym_t* symbol; + + symname_size = (info & ~(3 << 30)) >> 8; + + if ((info & (1 << 30)) != 0) + { + symname = rap->strtab + symname_size; + } + else + { + if (symname_size > (SYMNAME_BUFFER_SIZE - 1)) + { + free (symname_buffer); + rtems_rtl_set_error (EINVAL, "reloc symbol too big"); + return false; + } + + if (!rtems_rtl_obj_comp_read (rap->decomp, symname_buffer, symname_size)) + { + free (symname_buffer); + return false; + } + + symname_buffer[symname_size] = '\0'; + symname = symname_buffer; + } + + symbol = rtems_rtl_symbol_obj_find (obj, symname); + + if (!symbol) + { + rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname); + free (symname_buffer); + return false; + } + + symvalue = (Elf_Word) symbol->value; + } + + if (is_rela) + { + Elf_Rela rela; + + rela.r_offset = offset; + rela.r_info = type; + + if ((info & (1 << 31)) == 0) + rela.r_addend = 0; + else rela.r_addend = addend; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf (" %2d: rela: type:%-2d off:%lu addend:%d" \ + " symname=%s symtype=%lu symvalue=0x%08lx\n", + r, (int) type, offset, (int) addend, + symname, symtype, symvalue); + + if (!rtems_rtl_elf_relocate_rela (obj, &rela, targetsect, + symname, symtype, symvalue)) + { + free (symname_buffer); + return false; + } + } + else + { + Elf_Rel rel; + + rel.r_offset = offset; + rel.r_info = type; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf (" %2d: rel: type:%-2d off:%lu" \ + " symname=%s symtype=%lu symvalue=0x%08lx\n", + r, (int) type, offset, + symname, symtype, symvalue); + + if (!rtems_rtl_elf_relocate_rel (obj, &rel, targetsect, + symname, symtype, symvalue)) + { + free (symname_buffer); + return false; + } + } + } + } + + free (symname_buffer); + + return true; +} + +/** + * The structure of obj->detail is + * + * |object_detail(0..obj_num)|section_detail(0..sec_num[0..obj_num])| + * obj_name(0..obj_num)|section_name(0..sec_num[0..obj_num]) + * + */ +static bool +rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) +{ + struct link_map* tmp1; + section_detail* tmp2; + uint32_t obj_detail_size; + uint32_t pos = 0; + int i,j; + + obj_detail_size = sizeof (struct link_map) * obj->obj_num; + + for (i = 0; i < obj->obj_num; ++i) + { + obj_detail_size += (obj->sec_num[i] * sizeof (section_detail)); + } + + obj->detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, + obj_detail_size + rap->strtable_size, true); + + if (!obj->detail) + { + rap->strtable_size = 0; + rtems_rtl_set_error (ENOMEM, "no memory for obj global syms"); + return false; + } + + rap->strtable = obj->detail + obj_detail_size; + + /* Read the obj names and section names */ + if (!rtems_rtl_obj_comp_read (rap->decomp, rap->strtable, + rap->strtable_size)) + { + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj->detail); + return false; + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + { + if (rap->rpathlen > 0) + printf ("File rpath:\n"); + } + + while (pos < rap->rpathlen) + { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + { + printf (" %s\n", rap->strtable + pos); + } + pos = pos + strlen (rap->strtable + pos) + 1; + } + + if (rap->rpathlen > 0) + pos = rap->rpathlen; + + for (i = 0; i < obj->obj_num; ++i) + { + tmp1 = (struct link_map*) (obj->detail) + i; + tmp1->name = rap->strtable + pos; + tmp1->sec_num = obj->sec_num[i]; + tmp1->rpathlen = rap->rpathlen; + tmp1->rpath = (char*) rap->strtable; + pos += strlen (tmp1->name) + 1; + + if (!i) + { + tmp1->l_next = NULL; + tmp1->l_prev = NULL; + } + else + { + (tmp1 - 1)->l_next = tmp1; + tmp1->l_prev = tmp1 - 1; + tmp1->l_next = NULL; + } + } + + tmp2 =(section_detail*) ((struct link_map*) (obj->detail) + obj->obj_num); + + for (i = 0; i < obj->obj_num; ++i) + { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + { + printf ("File %d: %s\n", i, ((struct link_map*) obj->detail + i)->name); + printf ("Section: %d sections\n",(unsigned int) obj->sec_num[i]); + } + + ((struct link_map*)obj->detail + i)->sec_detail = tmp2; + + for (j = 0; j < obj->sec_num[i]; ++j) + { + uint32_t name; + uint32_t rap_id; + uint32_t offset; + uint32_t size; + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &name) || + !rtems_rtl_rap_read_uint32 (rap->decomp, &offset) || + !rtems_rtl_rap_read_uint32 (rap->decomp, &size)) + { + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->detail); + return false; + } + + rap_id = offset >> 28; + offset = offset & 0xfffffff; + + tmp2->name = rap->strtable + name; + tmp2->offset = offset; + tmp2->rap_id = rap_id; + tmp2->size = size; + pos += strlen (tmp2->name) + 1; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + { + printf ("name:%16s offset:0x%08x rap_id:%d size:0x%x\n", + tmp2->name, (unsigned int) tmp2->offset, + (unsigned int) tmp2->rap_id, (unsigned int) tmp2->size); + } + + tmp2 += 1; + } + } + return true; +} + +static bool +rtems_rtl_rap_load_symbols (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) +{ + rtems_rtl_obj_sym_t* gsym; + int sym; + + obj->global_size = + rap->symbols * sizeof (rtems_rtl_obj_sym_t) + rap->strtab_size; + + obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, + obj->global_size, true); + if (!obj->global_table) + { + obj->global_size = 0; + rtems_rtl_set_error (ENOMEM, "no memory for obj global syms"); + return false; + } + + obj->global_syms = rap->symbols; + + rap->strtab = (((char*) obj->global_table) + + (rap->symbols * sizeof (rtems_rtl_obj_sym_t))); + + if (!rtems_rtl_obj_comp_read (rap->decomp, rap->strtab, rap->strtab_size)) + return false; + + for (sym = 0, gsym = obj->global_table; sym < rap->symbols; ++sym) + { + rtems_rtl_obj_sect_t* symsect; + uint32_t data; + uint32_t name; + uint32_t value; + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &data) || + !rtems_rtl_rap_read_uint32 (rap->decomp, &name) || + !rtems_rtl_rap_read_uint32 (rap->decomp, &value)) + { + free (obj->global_table); + obj->global_table = NULL; + obj->global_syms = 0; + obj->global_size = 0; + return false; + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) + printf ("rtl: sym:load: data=0x%08lx name=0x%08lx value=0x%08lx\n", + data, name, value); + + /* + * If there is a globally exported symbol already present and this + * symbol is not weak raise an error. If the symbol is weak and present + * globally ignore this symbol and use the global one and if it is not + * present take this symbol global or weak. We accept the first weak + * symbol we find and make it globally exported. + */ + if (rtems_rtl_symbol_global_find (rap->strtab + name) && + (ELF_ST_BIND (data & 0xffff) != STB_WEAK)) + { + rtems_rtl_set_error (EINVAL, + "duplicate global symbol: %s", rap->strtab + name); + free (obj->global_table); + obj->global_table = NULL; + obj->global_syms = 0; + obj->global_size = 0; + return false; + } + + symsect = rtems_rtl_obj_find_section_by_index (obj, data >> 16); + if (!symsect) + { + free (obj->global_table); + obj->global_table = NULL; + obj->global_syms = 0; + obj->global_size = 0; + rtems_rtl_set_error (EINVAL, "section index not found: %lu", data >> 16); + return false; + } + + rtems_chain_set_off_chain (&gsym->node); + gsym->name = rap->strtab + name; + gsym->value = (uint8_t*) (value + symsect->base); + gsym->data = data & 0xffff; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) + printf ("rtl: sym:add:%-2d name:%-20s bind:%-2d type:%-2d val:%8p sect:%d\n", + sym, gsym->name, + (int) ELF_ST_BIND (data & 0xffff), + (int) ELF_ST_TYPE (data & 0xffff), + gsym->value, (int) (data >> 16)); + + ++gsym; + } + + return true; +} + +static bool +rtems_rtl_rap_parse_header (uint8_t* rhdr, + size_t* rhdr_len, + uint32_t* length, + uint32_t* version, + uint32_t* compression, + uint32_t* checksum) +{ + char* sptr = (char*) rhdr; + char* eptr; + + *rhdr_len = 0; + + /* + * "RAP," = 4 bytes, total 4 + */ + + if ((rhdr[0] != 'R') || (rhdr[1] != 'A') || (rhdr[2] != 'P') || (rhdr[3] != ',')) + return false; + + sptr = sptr + 4; + + /* + * "00000000," = 9 bytes, total 13 + */ + + *length = strtoul (sptr, &eptr, 10); + + if (*eptr != ',') + return false; + + sptr = eptr + 1; + + /* + * "0000," = 5 bytes, total 18 + */ + + *version = strtoul (sptr, &eptr, 10); + + if (*eptr != ',') + return false; + + sptr = eptr + 1; + + /* + * "NONE," and "LZ77," = 5 bytes, total 23 + */ + + if ((sptr[0] == 'N') && + (sptr[1] == 'O') && + (sptr[2] == 'N') && + (sptr[3] == 'E')) + { + *compression = RTEMS_RTL_COMP_NONE; + eptr = sptr + 4; + } + else if ((sptr[0] == 'L') && + (sptr[1] == 'Z') && + (sptr[2] == '7') && + (sptr[3] == '7')) + { + *compression = RTEMS_RTL_COMP_LZ77; + eptr = sptr + 4; + } + else + return false; + + if (*eptr != ',') + return false; + + sptr = eptr + 1; + + /* + * "00000000," = 9 bytes, total 32 + */ + *checksum = strtoul (sptr, &eptr, 16); + + /* + * "\n" = 1 byte, total 33 + */ + if (*eptr != '\n') + return false; + + *rhdr_len = ((uint8_t*) eptr) - rhdr + 1; + + return true; +} + +bool +rtems_rtl_rap_file_check (rtems_rtl_obj_t* obj, int fd) +{ + rtems_rtl_obj_cache_t* header; + uint8_t* rhdr = NULL; + size_t rlen = 64; + uint32_t length = 0; + uint32_t version = 0; + uint32_t compression = 0; + uint32_t checksum = 0; + + rtems_rtl_obj_caches (&header, NULL, NULL); + + if (!rtems_rtl_obj_cache_read (header, fd, obj->ooffset, + (void**) &rhdr, &rlen)) + return false; + + if (!rtems_rtl_rap_parse_header (rhdr, + &rlen, + &length, + &version, + &compression, + &checksum)) + return false; + + return true; +} + +bool +rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd) +{ + rtems_rtl_rap_t rap = { 0 }; + uint8_t* rhdr = NULL; + size_t rlen = 64; + int section; + + rtems_rtl_obj_caches (&rap.file, NULL, NULL); + + if (!rtems_rtl_obj_cache_read (rap.file, fd, obj->ooffset, + (void**) &rhdr, &rlen)) + return false; + + if (!rtems_rtl_rap_parse_header (rhdr, + &rlen, + &rap.length, + &rap.version, + &rap.compression, + &rap.checksum)) + { + rtems_rtl_set_error (EINVAL, "invalid RAP file format"); + return false; + } + + /* + * Set up the decompressor. + */ + rtems_rtl_obj_comp (&rap.decomp, rap.file, fd, rap.compression, + rlen + obj->ooffset); + + /* + * uint32_t: machinetype + * uint32_t: datatype + * uint32_t: class + */ + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input machine=%lu\n", + rtems_rtl_obj_comp_input (rap.decomp)); + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.machinetype)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: machinetype=%lu\n", rap.machinetype); + + if (!rtems_rtl_rap_machine_check (rap.machinetype)) + { + rtems_rtl_set_error (EINVAL, "invalid machinetype"); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.datatype)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: datatype=%lu\n", rap.datatype); + + if (!rtems_rtl_rap_datatype_check (rap.datatype)) + { + rtems_rtl_set_error (EINVAL, "invalid datatype"); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.class)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: class=%lu\n", rap.class); + + if (!rtems_rtl_rap_class_check (rap.class)) + { + rtems_rtl_set_error (EINVAL, "invalid class"); + return false; + } + + /* + * uint32_t: init + * uint32_t: fini + * uint32_t: symtab_size + * uint32_t: strtab_size + * uint32_t: relocs_size + */ + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input header=%lu\n", + rtems_rtl_obj_comp_input (rap.decomp)); + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.init)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.fini)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.symtab_size)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.strtab_size)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.relocs_size)) + return false; + + rap.symbols = rap.symtab_size / (3 * sizeof (uint32_t)); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: load: symtab=%lu (%lu) strtab=%lu relocs=%lu\n", + rap.symtab_size, rap.symbols, + rap.strtab_size, rap.relocs_size); + + /* + * Load the details + */ + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &obj->obj_num)) + return false; + + if (obj->obj_num > 0) + { + obj->sec_num = (uint32_t*) malloc (sizeof (uint32_t) * obj->obj_num); + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.rpathlen)) + return false; + + uint32_t i; + for (i = 0; i < obj->obj_num; ++i) + { + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &(obj->sec_num[i]))) + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.strtable_size)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + printf ("rtl: rap: details: obj_num=%lu\n", obj->obj_num); + + if (!rtems_rtl_rap_load_details (&rap, obj)) + return false; + } + + /* + * uint32_t: text_size + * uint32_t: text_alignment + * uint32_t: const_size + * uint32_t: const_alignment + * uint32_t: ctor_size + * uint32_t: ctor_alignment + * uint32_t: dtor_size + * uint32_t: dtor_alignment + * uint32_t: data_size + * uint32_t: data_alignment + * uint32_t: bss_size + * uint32_t: bss_alignment + */ + + for (section = 0; section < RTEMS_RTL_RAP_SECS; ++section) + { + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.secs[section].size)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.secs[section].alignment)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT)) + printf ("rtl: rap: %s: size=%lu align=%lu\n", + rap_sections[section].name, + rap.secs[section].size, + rap.secs[section].alignment); + + if (!rtems_rtl_obj_add_section (obj, + section, + rap_sections[section].name, + rap.secs[section].size, + 0, + rap.secs[section].alignment, + 0, 0, + rap_sections[section].flags)) + return false; + } + + /** obj->entry = (void*)(uintptr_t) ehdr.e_entry; */ + + if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_rap_loader, &rap)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input symbols=%lu\n", + rtems_rtl_obj_comp_input (rap.decomp)); + + if (!rtems_rtl_rap_load_symbols (&rap, obj)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input relocs=%lu\n", + rtems_rtl_obj_comp_input (rap.decomp)); + + if (!rtems_rtl_rap_relocate (&rap, obj)) + return false; + + return true; +} + +rtems_rtl_loader_format_t* +rtems_rtl_rap_file_sig (void) +{ + return &rap_sig; +} diff --git a/cpukit/libdl/rtl-rap.h b/cpukit/libdl/rtl-rap.h new file mode 100644 index 0000000000..54c1268696 --- /dev/null +++ b/cpukit/libdl/rtl-rap.h @@ -0,0 +1,54 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker ELF Headers + */ + +#if !defined (_RTEMS_RTL_RAP_H_) +#define _RTEMS_RTL_RAP_H_ + +#include "rtl-fwd.h" +#include "rtl-obj-fwd.h" +#include "rtl-sym.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * The RAP format check handler. + * + * @param obj The object being checked. + * @param fd The file descriptor. + */ +bool rtems_rtl_rap_file_check (rtems_rtl_obj_t* obj, int fd); + +/** + * The RAP format load handler. + * + * @param obj The object to load. + * @param fd The file descriptor. + */ +bool rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd); + +/** + * The RAP format signature handler. + * + * @return rtems_rtl_loader_format_t* The format's signature. + */ +rtems_rtl_loader_format_t* rtems_rtl_rap_file_sig (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-shell.c b/cpukit/libdl/rtl-shell.c new file mode 100644 index 0000000000..0e33e849ef --- /dev/null +++ b/cpukit/libdl/rtl-shell.c @@ -0,0 +1,389 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor Shell Commands + * + * A simple RTL command to aid using the RTL. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> + +//#if SIZEOF_OFF_T == 8 +#define PRIdoff_t PRIo64 +//#elif SIZEOF_OFF_T == 4 +//#define PRIdoff_t PRIo32 +//#else +//#error "unsupported size of off_t" +//#endif + +#include <stdio.h> +#include <string.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-chain-iterator.h" +#include "rtl-shell.h" +#include "rtl-trace.h" + +/** + * The type of the shell handlers we have. + */ +typedef int (*rtems_rtl_shell_handler_t) (rtems_rtl_data_t* rtl, int argc, char *argv[]); + +/** + * Table of handlers we parse to invoke the command. + */ +typedef struct +{ + const char* name; /**< The sub-command's name. */ + rtems_rtl_shell_handler_t handler; /**< The sub-command's handler. */ + const char* help; /**< The sub-command's help. */ +} rtems_rtl_shell_cmd_t; + +/** + * Object summary data. + */ +typedef struct +{ + int count; /**< The number of object files. */ + size_t exec; /**< The amount of executable memory allocated. */ + size_t symbols; /**< The amount of symbol memory allocated. */ +} rtems_rtl_obj_summary_t; + +/** + * Object summary iterator. + */ +static bool +rtems_rtl_obj_summary_iterator (rtems_chain_node* node, void* data) +{ + rtems_rtl_obj_summary_t* summary = data; + rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) node; + ++summary->count; + summary->exec += obj->exec_size; + summary->symbols += obj->global_size; + return true; +} + +/** + * Count the number of symbols. + */ +static int +rtems_rtl_count_symbols (rtems_rtl_data_t* rtl) +{ + int count; + int bucket; + for (count = 0, bucket = 0; bucket < rtl->globals.nbuckets; ++bucket) + count += rtems_rtl_chain_count (&rtl->globals.buckets[bucket]); + return count; +} + +static int +rtems_rtl_shell_status (rtems_rtl_data_t* rtl, int argc, char *argv[]) +{ + rtems_rtl_obj_summary_t summary; + size_t total_memory; + + summary.count = 0; + summary.exec = 0; + summary.symbols = 0; + rtems_rtl_chain_iterate (&rtl->objects, + rtems_rtl_obj_summary_iterator, + &summary); + /* + * Currently does not include the name strings in the obj struct. + */ + total_memory = + sizeof (*rtl) + (summary.count * sizeof (rtems_rtl_obj_t)) + + summary.exec + summary.symbols; + + printf ("Runtime Linker Status:\n"); + printf (" paths: %s\n", rtl->paths); + printf (" objects: %d\n", summary.count); + printf (" total memory: %zi\n", total_memory); + printf (" exec memory: %zi\n", summary.exec); + printf (" sym memory: %zi\n", summary.symbols); + printf (" symbols: %d\n", rtems_rtl_count_symbols (rtl)); + + return 0; +} + +/** + * Object print data. + */ +typedef struct +{ + rtems_rtl_data_t* rtl; /**< The RTL data. */ + int indent; /**< Spaces to indent. */ + bool oname; /**< Print object names. */ + bool names; /**< Print details of all names. */ + bool memory_map; /**< Print the memory map. */ + bool symbols; /**< Print the global symbols. */ + bool base; /**< Include the base object file. */ +} rtems_rtl_obj_print_t; + +/** + * Return the different between 2 void*. + */ +static size_t +rtems_rtl_delta_voids (void* higher, void* lower) +{ + char* ch = higher; + char* cl = lower; + return ch - cl; +} + +/** + * Parse an argument. + */ +static bool +rtems_rtl_parse_arg (const char* opt, int argc, char *argv[]) +{ + int arg; + for (arg = 0; arg < argc; ++arg) + if (strncmp (opt, argv[arg], 2) == 0) + return true; + return false; +} + +/** + * See if -b for base is set. + */ +static bool +rtems_rtl_base_arg (int argc, char *argv[]) +{ + return rtems_rtl_parse_arg ("-b", argc, argv); +} + +/** + * See if -s for base is set. + */ +static bool +rtems_rtl_symbols_arg (int argc, char *argv[]) +{ + return rtems_rtl_parse_arg ("-s", argc, argv); +} + +/** + * Object printer. + */ +static bool +rtems_rtl_obj_printer (rtems_rtl_obj_print_t* print, rtems_rtl_obj_t* obj) +{ + char flags_str[33]; + + /* + * Skip the base module unless asked to show it. + */ + if (!print->base && (obj == print->rtl->base)) + return true; + + if (print->oname) + { + printf ("%-*cobject name : %s\n", + print->indent, ' ', rtems_rtl_obj_oname (obj)); + } + if (print->names) + { + printf ("%-*cfile name : %s\n", + print->indent, ' ', rtems_rtl_obj_fname (obj)); + printf ("%-*carchive name : %s\n", + print->indent, ' ', rtems_rtl_obj_aname (obj)); + strcpy (flags_str, "--"); + if (obj->flags & RTEMS_RTL_OBJ_LOCKED) + flags_str[0] = 'L'; + if (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) + flags_str[1] = 'U'; + printf ("%-*cflags : %s\n", print->indent, ' ', flags_str); + printf ("%-*cfile offset : %" PRIdoff_t "\n", print->indent, ' ', obj->ooffset); + printf ("%-*cfile size : %zi\n", print->indent, ' ', obj->fsize); + } + if (print->memory_map) + { + printf ("%-*cexec size : %zi\n", print->indent, ' ', obj->exec_size); + printf ("%-*ctext base : %p (%zi)\n", print->indent, ' ', + obj->text_base, rtems_rtl_delta_voids (obj->const_base, obj->text_base)); + printf ("%-*cconst base : %p (%zi)\n", print->indent, ' ', + obj->const_base, rtems_rtl_delta_voids (obj->data_base, obj->const_base)); + printf ("%-*cdata base : %p (%zi)\n", print->indent, ' ', + obj->data_base, rtems_rtl_delta_voids (obj->bss_base, obj->data_base)); + printf ("%-*cbss base : %p (%zi)\n", print->indent, ' ', + obj->bss_base, obj->bss_size); + } + printf ("%-*cunresolved : %lu\n", print->indent, ' ', obj->unresolved); + printf ("%-*csymbols : %zi\n", print->indent, ' ', obj->global_syms); + printf ("%-*csymbol memory : %zi\n", print->indent, ' ', obj->global_size); + if (print->symbols) + { + int max_len = 0; + int s; + for (s = 0; s < obj->global_syms; ++s) + { + int len = strlen (obj->global_table[s].name); + if (len > max_len) + max_len = len; + } + for (s = 0; s < obj->global_syms; ++s) + printf ("%-*c%-*s = %p\n", print->indent + 2, ' ', + max_len, obj->global_table[s].name, obj->global_table[s].value); + } + printf ("\n"); + return true; +} + +/** + * Object unresolved symbols printer. + */ +static bool +rtems_rtl_unresolved_printer (rtems_rtl_unresolv_rec_t* rec, + void* data) +{ + rtems_rtl_obj_print_t* print = (rtems_rtl_obj_print_t*) data; + if (rec->type == rtems_rtl_unresolved_name) + printf ("%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name); + return false; +} + +/** + * Object print iterator. + */ +static bool +rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data) +{ + rtems_rtl_obj_print_t* print = data; + rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) node; + return rtems_rtl_obj_printer (print, obj); +} + +static int +rtems_rtl_shell_list (rtems_rtl_data_t* rtl, int argc, char *argv[]) +{ + rtems_rtl_obj_print_t print; + print.rtl = rtl; + print.indent = 1; + print.oname = true; + print.names = true; + print.memory_map = true; + print.symbols = rtems_rtl_symbols_arg (argc, argv); + print.base = false; + rtems_rtl_chain_iterate (&rtl->objects, + rtems_rtl_obj_print_iterator, + &print); + return 0; +} + +static int +rtems_rtl_shell_sym (rtems_rtl_data_t* rtl, int argc, char *argv[]) +{ + rtems_rtl_obj_print_t print; + print.rtl = rtl; + print.indent = 1; + print.oname = true; + print.names = false; + print.memory_map = false; + print.symbols = true; + print.base = rtems_rtl_base_arg (argc, argv); + rtems_rtl_chain_iterate (&rtl->objects, + rtems_rtl_obj_print_iterator, + &print); + printf ("Unresolved:\n"); + rtems_rtl_unresolved_interate (rtems_rtl_unresolved_printer, &print); + return 0; +} + +static int +rtems_rtl_shell_object (rtems_rtl_data_t* rtl, int argc, char *argv[]) +{ + return 0; +} + +static void +rtems_rtl_shell_usage (const char* arg) +{ + printf ("%s: Runtime Linker\n", arg); + printf (" %s [-hl] <command>\n", arg); + printf (" where:\n"); + printf (" command: A n RTL command. See -l for a list plus help.\n"); + printf (" -h: This help\n"); + printf (" -l: The command list.\n"); +} + +int +rtems_rtl_shell_command (int argc, char* argv[]) +{ + const rtems_rtl_shell_cmd_t table[] = + { + { "status", rtems_rtl_shell_status, + "Display the status of the RTL" }, + { "list", rtems_rtl_shell_list, + "\tList the object files currently loaded" }, + { "sym", rtems_rtl_shell_sym, + "\tDisplay the symbols, sym [<name>], sym -o <obj> [<name>]" }, + { "obj", rtems_rtl_shell_object, + "\tDisplay the object details, obj <name>" } + }; + + int arg; + int t; + + for (arg = 1; arg < argc; arg++) + { + if (argv[arg][0] != '-') + break; + + switch (argv[arg][1]) + { + case 'h': + rtems_rtl_shell_usage (argv[0]); + return 0; + case 'l': + printf ("%s: commands are:\n", argv[0]); + for (t = 0; + t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd_t)); + ++t) + printf (" %s\t%s\n", table[t].name, table[t].help); + return 0; + default: + printf ("error: unknown option: %s\n", argv[arg]); + return 1; + } + } + + if ((argc - arg) < 1) + printf ("error: you need to provide a command, try %s -h\n", argv[0]); + else + { + for (t = 0; + t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd_t)); + ++t) + { + if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0) + { + rtems_rtl_data_t* rtl = rtems_rtl_data (); + int r; + if (!rtl) + { + printf ("error: cannot lock the linker\n"); + return 1; + } + r = table[t].handler (rtl, argc - 1, argv + 1); + rtems_rtl_unlock (); + return r; + } + } + printf ("error: command not found: %s (try -h)\n", argv[arg]); + } + + return 1; +} diff --git a/cpukit/libdl/rtl-shell.h b/cpukit/libdl/rtl-shell.h new file mode 100644 index 0000000000..ac9bb25c03 --- /dev/null +++ b/cpukit/libdl/rtl-shell.h @@ -0,0 +1,39 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker ELF Shell Support. + */ + +#if !defined (_RTEMS_RTL_SHELL_H_) +#define _RTEMS_RTL_SHELL_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <stdint.h> + +/** + * The RTL single shell command contains sub-commands. + * + * @param argc The argument count. + * @param argv Array of argument strings. + * @retval 0 No error. + * @return int The exit code. + */ +int rtems_rtl_shell_command (int argc, char* argv[]); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-string.c b/cpukit/libdl/rtl-string.c new file mode 100644 index 0000000000..4a49b77fe6 --- /dev/null +++ b/cpukit/libdl/rtl-string.c @@ -0,0 +1,32 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker String managment. + */ + +#include <string.h> + +#include "rtl-allocator.h" +#include "rtl-string.h" + +char* +rtems_rtl_strdup (const char *s1) +{ + size_t len = strlen (s1); + char* s2 = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, false); + if (s2) + { + memcpy (s2, s1, len); + s2[len] = '\0'; + } + return s2; +} diff --git a/cpukit/libdl/rtl-string.h b/cpukit/libdl/rtl-string.h new file mode 100644 index 0000000000..a9ce6f51b4 --- /dev/null +++ b/cpukit/libdl/rtl-string.h @@ -0,0 +1,37 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker String managment. + */ + +#if !defined (_RTEMS_RTL_STRING_H_) +#define _RTEMS_RTL_STRING_H_ + +#include "rtl-indirect-ptr.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * A string duplicate that uses the RTL allocator. + * + * @param s1 The string to duplicate. + * @return char* The copy of the string. NULL if there is no memory. + */ +char* rtems_rtl_strdup (const char *s1); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-sym.c b/cpukit/libdl/rtl-sym.c new file mode 100644 index 0000000000..f8063948bd --- /dev/null +++ b/cpukit/libdl/rtl-sym.c @@ -0,0 +1,245 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object File Symbol Table. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> +#include <stdio.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-error.h" +#include "rtl-sym.h" +#include "rtl-trace.h" + +/** + * The single symbol forced into the global symbol table that is used to load a + * symbol table from an object file. + */ +static rtems_rtl_obj_sym_t global_sym_add = +{ + .name = "rtems_rtl_base_sym_global_add", + .value = (void*) rtems_rtl_base_sym_global_add +}; + +static uint_fast32_t +rtems_rtl_symbol_hash (const char *s) +{ + uint_fast32_t h = 5381; + unsigned char c; + for (c = *s; c != '\0'; c = *++s) + h = h * 33 + c; + return h & 0xffffffff; +} + +static void +rtems_rtl_symbol_global_insert (rtems_rtl_symbols_t* symbols, + rtems_rtl_obj_sym_t* symbol) +{ + uint_fast32_t hash = rtems_rtl_symbol_hash (symbol->name); + rtems_chain_append (&symbols->buckets[hash % symbols->nbuckets], + &symbol->node); +} + +bool +rtems_rtl_symbol_table_open (rtems_rtl_symbols_t* symbols, + size_t buckets) +{ + symbols->buckets = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, + buckets * sizeof (rtems_chain_control), + true); + if (!symbols->buckets) + { + rtems_rtl_set_error (ENOMEM, "no memory for global symbol table"); + return false; + } + symbols->nbuckets = buckets; + for (buckets = 0; buckets < symbols->nbuckets; ++buckets) + rtems_chain_initialize_empty (&symbols->buckets[buckets]); + rtems_rtl_symbol_global_insert (symbols, &global_sym_add); + return true; +} + +void +rtems_rtl_symbol_table_close (rtems_rtl_symbols_t* symbols) +{ + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, symbols->buckets); +} + +bool +rtems_rtl_symbol_global_add (rtems_rtl_obj_t* obj, + const unsigned char* esyms, + unsigned int size) +{ + rtems_rtl_symbols_t* symbols; + rtems_rtl_obj_sym_t* sym; + size_t count; + size_t s; + uint32_t marker; + + count = 0; + s = 0; + while ((s < size) && (esyms[s] != 0)) + { + int l = strlen ((char*) &esyms[s]); + if ((esyms[s + l] != '\0') || ((s + l) > size)) + { + rtems_rtl_set_error (EINVAL, "invalid exported symbol table"); + return false; + } + ++count; + s += l + sizeof (unsigned long) + 1; + } + + /* + * Check this is the correct end of the table. + */ + marker = esyms[s + 1]; + marker <<= 8; + marker |= esyms[s + 2]; + marker <<= 8; + marker |= esyms[s + 3]; + marker <<= 8; + marker |= esyms[s + 4]; + + if (marker != 0xdeadbeefUL) + { + rtems_rtl_set_error (ENOMEM, "invalid export symbol table"); + return false; + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) + printf ("rtl: global symbol add: %zi\n", count); + + obj->global_size = count * sizeof (rtems_rtl_obj_sym_t); + obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, + obj->global_size, true); + if (!obj->global_table) + { + obj->global_size = 0; + rtems_rtl_set_error (ENOMEM, "no memory for global symbols"); + return false; + } + + symbols = rtems_rtl_global_symbols (); + + s = 0; + sym = obj->global_table; + + while ((s < size) && (esyms[s] != 0)) + { + /* + * Copy the void* using a union and memcpy to avoid any strict aliasing or + * alignment issues. The variable length of the label and the packed nature + * of the table means casting is not suitable. + */ + union { + uint8_t data[sizeof (void*)]; + void* value; + } copy_voidp; + int b; + + sym->name = (const char*) &esyms[s]; + s += strlen (sym->name) + 1; + for (b = 0; b < sizeof (void*); ++b, ++s) + copy_voidp.data[b] = esyms[s]; + sym->value = copy_voidp.value; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) + printf ("rtl: esyms: %s -> %8p\n", sym->name, sym->value); + if (rtems_rtl_symbol_global_find (sym->name) == NULL) + rtems_rtl_symbol_global_insert (symbols, sym); + ++sym; + } + + obj->global_syms = count; + + return true; +} + +rtems_rtl_obj_sym_t* +rtems_rtl_symbol_global_find (const char* name) +{ + rtems_rtl_symbols_t* symbols; + uint_fast32_t hash; + rtems_chain_control* bucket; + rtems_chain_node* node; + + symbols = rtems_rtl_global_symbols (); + + hash = rtems_rtl_symbol_hash (name); + bucket = &symbols->buckets[hash % symbols->nbuckets]; + node = rtems_chain_first (bucket); + + while (!rtems_chain_is_tail (bucket, node)) + { + rtems_rtl_obj_sym_t* sym = (rtems_rtl_obj_sym_t*) node; + /* + * Use the hash. I could add this to the symbol but it uses more memory. + */ + if (strcmp (name, sym->name) == 0) + return sym; + node = rtems_chain_next (node); + } + + return NULL; +} + +rtems_rtl_obj_sym_t* +rtems_rtl_symbol_obj_find (rtems_rtl_obj_t* obj, const char* name) +{ + rtems_rtl_obj_sym_t* sym; + size_t s; + /* + * Check the object file's symbols first. If not found search the + * global symbol table. + */ + for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym) + if (strcmp (name, sym->name) == 0) + return sym; + return rtems_rtl_symbol_global_find (name); +} + +void +rtems_rtl_symbol_obj_add (rtems_rtl_obj_t* obj) +{ + rtems_rtl_symbols_t* symbols; + rtems_rtl_obj_sym_t* sym; + size_t s; + + symbols = rtems_rtl_global_symbols (); + + for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym) + rtems_rtl_symbol_global_insert (symbols, sym); +} + +void +rtems_rtl_symbol_obj_erase (rtems_rtl_obj_t* obj) +{ + if (obj->global_table) + { + rtems_rtl_obj_sym_t* sym; + size_t s; + for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym) + if (!rtems_chain_is_node_off_chain (&sym->node)) + rtems_chain_extract (&sym->node); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table); + obj->global_table = NULL; + obj->global_size = 0; + obj->global_syms = 0; + } +} diff --git a/cpukit/libdl/rtl-sym.h b/cpukit/libdl/rtl-sym.h new file mode 100644 index 0000000000..b793a547dc --- /dev/null +++ b/cpukit/libdl/rtl-sym.h @@ -0,0 +1,128 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object File Symbol Table. + */ + +#if !defined (_RTEMS_RTL_SYM_H_) +#define _RTEMS_RTL_SYM_H_ + +#include <rtems.h> +#include "rtl-obj-fwd.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * An object file symbol. + */ +typedef struct rtems_rtl_obj_sym_s +{ + rtems_chain_node node; /**< The node's link in the chain. */ + const char* name; /**< The symbol's name. */ + void* value; /**< The value of the symbol. */ + uint32_t data; /**< Format specific data. */ +} rtems_rtl_obj_sym_t; + +/** + * Table of symbols stored in a hash table. + */ +typedef struct rtems_rtl_symbols_s +{ + rtems_chain_control* buckets; + size_t nbuckets; +} rtems_rtl_symbols_t; + +/** + * Open a symbol table with the specified number of buckets. + * + * @param symbols The symbol table to open. + * @param buckets The number of buckets in the hash table. + * @retval true The symbol is open. + * @retval false The symbol table could not created. The RTL + * error has the error. + */ +bool rtems_rtl_symbol_table_open (rtems_rtl_symbols_t* symbols, + size_t buckets); + +/** + * Close the table and erase the hash table. + * + * @param symbols Close the symbol table. + */ +void rtems_rtl_symbol_table_close (rtems_rtl_symbols_t* symbols); + +/** + * Add a table of exported symbols to the symbol table. + * + * The export table is a series of symbol records and each record has two + * fields: + * + * 1. label + * 2. address + * + * The 'label' is an ASCIIZ string of variable length. The address is of size + * of an unsigned long for the target running the link editor. The byte order + * is defined by the machine type because the table should be built by the + * target compiler. + * + * The table is terminated with a nul string followed by the bytes 0xDE, 0xAD, + * 0xBE, and 0xEF. This avoids alignments issues. + * + * @param obj The object table the symbols are for. + * @param esyms The exported symbol table. + * @param size The size of the table in bytes. + */ +bool rtems_rtl_symbol_global_add (rtems_rtl_obj_t* obj, + const unsigned char* esyms, + unsigned int size); + +/** + * Find a symbol given the symbol label in the global symbol table. + * + * @param name The name as an ASCIIZ string. + * @retval NULL No symbol found. + * @return rtems_rtl_obj_sym_t* Reference to the symbol. + */ +rtems_rtl_obj_sym_t* rtems_rtl_symbol_global_find (const char* name); + +/** + * Find a symbol given the symbol label in the local object file. + * + * @param obj The object file to search. + * @param name The name as an ASCIIZ string. + * @retval NULL No symbol found. + * @return rtems_rtl_obj_sym_t* Reference to the symbol. + */ +rtems_rtl_obj_sym_t* rtems_rtl_symbol_obj_find (rtems_rtl_obj_t* obj, + const char* name); + +/** + * Add the object file's symbols to the global table. + * + * @param obj The object file the symbols are to be added. + */ +void rtems_rtl_symbol_obj_add (rtems_rtl_obj_t* obj); + +/** + * Erase the object file's symbols. + * + * @param obj The object file the symbols are to be erased from. + */ +void rtems_rtl_symbol_obj_erase (rtems_rtl_obj_t* obj); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-trace.c b/cpukit/libdl/rtl-trace.c new file mode 100644 index 0000000000..d577f9975e --- /dev/null +++ b/cpukit/libdl/rtl-trace.c @@ -0,0 +1,134 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor Trace + * + * A configurable tracer for the RTL. See the header file for the enable and + * disable. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> + +#include "rtl-trace.h" + +#if RTEMS_RTL_TRACE +static rtems_rtl_trace_mask rtems_rtl_trace_flags; + +bool +rtems_rtl_trace (rtems_rtl_trace_mask mask) +{ + bool result = false; + if (mask & rtems_rtl_trace_flags) + result = true; + return result; +} + +rtems_rtl_trace_mask +rtems_rtl_trace_set_mask (rtems_rtl_trace_mask mask) +{ + rtems_rtl_trace_mask state = rtems_rtl_trace_flags; + rtems_rtl_trace_flags |= mask; + return state; +} + +rtems_rtl_trace_mask +rtems_rtl_trace_clear_mask (rtems_rtl_trace_mask mask) +{ + rtems_rtl_trace_mask state = rtems_rtl_trace_flags; + rtems_rtl_trace_flags &= ~mask; + return state; +} + +int +rtems_rtl_trace_shell_command (int argc, char *argv[]) +{ + const char* table[] = + { + "load", + "unload", + "section", + "symbol", + "reloc", + "global-sym", + "load-sect", + "allocator", + "unresolved", + "detail" + }; + + rtems_rtl_trace_mask set_value = 0; + rtems_rtl_trace_mask clear_value = 0; + bool set = true; + int arg; + int t; + + for (arg = 1; arg < argc; arg++) + { + if (argv[arg][0] == '-') + { + switch (argv[arg][1]) + { + case 'h': + printf ("usage: %s [-hl] [set/clear] [flags]\n", argv[0]); + return 0; + case 'l': + printf ("%s: valid flags to set or clear are:\n", argv[0]); + for (t = 0; t < (sizeof (table) / sizeof (const char*)); t++) + printf (" %s\n", table[t]); + return 0; + default: + printf ("error: unknown option\n"); + return 1; + } + } + else + { + if (strcmp (argv[arg], "set") == 0) + set = true; + if (strcmp (argv[arg], "clear") == 0) + set = false; + else if (strcmp (argv[arg], "all") == 0) + { + if (set) + set_value = RTEMS_RTL_TRACE_ALL; + else + clear_value = RTEMS_RTL_TRACE_ALL; + } + else + { + for (t = 0; t < (sizeof (table) / sizeof (const char*)); t++) + { + if (strcmp (argv[arg], table[t]) == 0) + { + if (set) + set_value = 1 << t; + else + clear_value = 1 << t; + break; + } + } + } + + rtems_rtl_trace_flags |= set_value; + rtems_rtl_trace_flags &= ~clear_value; + } + } + + return 0; +} + +#endif diff --git a/cpukit/libdl/rtl-trace.h b/cpukit/libdl/rtl-trace.h new file mode 100644 index 0000000000..1a5ee973a5 --- /dev/null +++ b/cpukit/libdl/rtl-trace.h @@ -0,0 +1,100 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker ELF Trace Support. + */ + +#if !defined (_RTEMS_RTL_TRACE_H_) +#define _RTEMS_RTL_TRACE_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <stdbool.h> +#include <stdint.h> + +/** + * Set to 1 to build trace support in to the RTL code. + */ +#define RTEMS_RTL_TRACE 1 + +/** + * The type of the mask. + */ +typedef uint32_t rtems_rtl_trace_mask; + +/** + * List of tracing bits for the various parts of the link editor. + */ +#define RTEMS_RTL_TRACE_ALL (0xffffffffUL) +#define RTEMS_RTL_TRACE_LOAD (1UL << 0) +#define RTEMS_RTL_TRACE_UNLOAD (1UL << 1) +#define RTEMS_RTL_TRACE_SECTION (1UL << 2) +#define RTEMS_RTL_TRACE_SYMBOL (1UL << 3) +#define RTEMS_RTL_TRACE_RELOC (1UL << 4) +#define RTEMS_RTL_TRACE_GLOBAL_SYM (1UL << 5) +#define RTEMS_RTL_TRACE_LOAD_SECT (1UL << 6) +#define RTEMS_RTL_TRACE_ALLOCATOR (1UL << 7) +#define RTEMS_RTL_TRACE_UNRESOLVED (1UL << 8) +#define RTEMS_RTL_TRACE_DETAIL (1UL << 9) + +/** + * Call to check if this part is bring traced. If RTEMS_RTL_TRACE is defined to + * 0 the code is dead code elminiated when built with -Os, -O2, or higher. + * + * @param mask The part of the API to trace. + * @retval true Tracing is active for the mask. + * @retval false Do not trace. + */ +#if RTEMS_RTL_TRACE +bool rtems_rtl_trace (rtems_rtl_trace_mask mask); +#else +#define rtems_rtl_trace(_m) (0) +#endif + +/** + * Set the mask. + * + * @param mask The mask bits to set. + * @return The previous mask. + */ +#if RTEMS_RTL_TRACE +rtems_rtl_trace_mask rtems_rtl_trace_set_mask (rtems_rtl_trace_mask mask); +#else +#define rtems_rtl_trace_set_mask(_m) +#endif + +/** + * Clear the mask. + * + * @param mask The mask bits to clear. + * @return The previous mask. + */ +#if RTEMS_RTL_TRACE +rtems_rtl_trace_mask rtems_rtl_trace_clear_mask (rtems_rtl_trace_mask mask); +#else +#define rtems_rtl_trace_clear_mask(_m) +#endif + +/** + * Add shell trace shell command. + */ +#if RTEMS_RTL_TRACE +int rtems_rtl_trace_shell_command (int argc, char *argv[]); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c new file mode 100644 index 0000000000..0dbde0a48a --- /dev/null +++ b/cpukit/libdl/rtl-unresolved.c @@ -0,0 +1,471 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object File Unresolved Relocations Table. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> +#include <stdio.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-error.h" +#include "rtl-unresolved.h" +#include "rtl-trace.h" + +static rtems_rtl_unresolv_block_t* +rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved_t* unresolved) +{ + /* + * The block header contains a record. + */ + size_t size = + (sizeof(rtems_rtl_unresolv_block_t) + + (sizeof(rtems_rtl_unresolv_rec_t) * (unresolved->block_recs - 1))); + rtems_rtl_unresolv_block_t* block = + rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_EXTERNAL, size, true); + if (block) + rtems_chain_append (&unresolved->blocks, &block->link); + else + rtems_rtl_set_error (ENOMEM, "no memory for unresolved block"); + return block; +} + +static size_t +rtems_rtl_unresolved_name_recs (const char* name) +{ + size_t length = strlen (name); + return ((length + sizeof(rtems_rtl_unresolv_name_t) - 1) / + sizeof(rtems_rtl_unresolv_name_t)); +} + +static int +rtems_rtl_unresolved_rec_index (rtems_rtl_unresolv_block_t* block, + rtems_rtl_unresolv_rec_t* rec) +{ + return (rec - &block->rec) / sizeof (rtems_rtl_unresolv_rec_t); +} + +static rtems_rtl_unresolv_rec_t* +rtems_rtl_unresolved_rec_first (rtems_rtl_unresolv_block_t* block) +{ + return &block->rec; +} + +static rtems_rtl_unresolv_rec_t* +rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec_t* rec) +{ + + switch (rec->type) + { + case rtems_rtl_unresolved_empty: + /* + * Empty returns NULL. The end of the records in the block. + */ + rec = NULL; + break; + + case rtems_rtl_unresolved_name: + /* + * Determine how many records the name occupies. Round up. + */ + rec += ((rec->rec.name.length + sizeof(rtems_rtl_unresolv_name_t) - 1) / + sizeof(rtems_rtl_unresolv_name_t)); + break; + + case rtems_rtl_unresolved_reloc: + ++rec; + break; + + default: + break; + } + + return rec; +} + +static bool +rtems_rtl_unresolved_rec_is_last (rtems_rtl_unresolv_block_t* block, + rtems_rtl_unresolv_rec_t* rec) +{ + int index = (rec - &block->rec) / sizeof (rec); + return !rec || (index >= block->recs) || (rec->type == rtems_rtl_unresolved_empty); +} + +static rtems_rtl_unresolv_rec_t* +rtems_rtl_unresolved_rec_first_free (rtems_rtl_unresolv_block_t* block) +{ + return &block->rec + block->recs; +} + +static int +rtems_rtl_unresolved_find_name (rtems_rtl_unresolved_t* unresolved, + const char* name, + bool update_refcount) +{ + size_t length = strlen (name); + int index = 1; + + rtems_chain_node* node = rtems_chain_first (&unresolved->blocks); + while (!rtems_chain_is_tail (&unresolved->blocks, node)) + { + rtems_rtl_unresolv_block_t* block = (rtems_rtl_unresolv_block_t*) node; + rtems_rtl_unresolv_rec_t* rec = rtems_rtl_unresolved_rec_first (block); + + while (!rtems_rtl_unresolved_rec_is_last (block, rec)) + { + if (rec->type == rtems_rtl_unresolved_name) + { + if ((rec->rec.name.length == length) + && (strcmp (rec->rec.name.name, name))) + { + if (update_refcount) + ++rec->rec.name.refs; + return index; + } + ++index; + } + rec = rtems_rtl_unresolved_rec_next (rec); + } + + node = rtems_chain_next (node); + } + + return 0 - index; +} + +/** + * Struct to pass relocation data in the interator. + */ +typedef struct rtems_rtl_unresolved_reloc_data_s +{ + uint16_t name; /**< Name index. */ + rtems_rtl_unresolv_rec_t* name_rec; /**< Name record. */ + rtems_rtl_obj_sym_t* sym; /**< The symbol record. */ +} rtems_rtl_unresolved_reloc_data_t; + +static bool +rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec_t* rec, + void* data) +{ + if (rec->type == rtems_rtl_unresolved_reloc) + { + rtems_rtl_unresolved_reloc_data_t* rd; + rd = (rtems_rtl_unresolved_reloc_data_t*) data; + + if (rec->rec.reloc.name == rd->name) + { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) + printf ("rtl: unresolv: resolve reloc: %s\n", rd->name_rec->rec.name.name); + + rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym); + + /* + * Set the object pointer to NULL to indicate the record is not used + * anymore. Update the reference count of the name. The sweep after + * relocating will remove the reloc records with obj set to NULL and + * names with a reference count of 0. + */ + rec->rec.reloc.obj = NULL; + if (rd->name_rec && rd->name_rec->rec.name.refs) + --rd->name_rec->rec.name.refs; + } + } + return false; +} + +static bool +rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec_t* rec, + void* data) +{ + if (rec->type == rtems_rtl_unresolved_name) + { + rtems_rtl_unresolved_reloc_data_t* rd; + rd = (rtems_rtl_unresolved_reloc_data_t*) data; + + ++rd->name; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) + printf ("rtl: unresolv: lookup: %d: %s\n", rd->name, rec->rec.name.name); + + rd->sym = rtems_rtl_symbol_global_find (rec->rec.name.name); + + if (rd->sym) + { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) + printf ("rtl: unresolv: found: %s\n", rec->rec.name.name); + + rd->name_rec = rec; + + rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_reloc, rd); + + rd->name_rec = NULL; + rd->sym = NULL; + } + } + + return false; +} + +static void +rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block_t* block, + rtems_rtl_unresolv_rec_t* rec, + size_t count, + size_t recs_per_block) +{ + size_t index = rtems_rtl_unresolved_rec_index (block, rec); + size_t bytes = + (block->recs - index - count) * sizeof (rtems_rtl_unresolv_rec_t); + if (bytes) + memmove (rec, rec + count, bytes); + --block->recs; + bytes = count * sizeof (rtems_rtl_unresolv_rec_t); + memset (&block->rec + block->recs, 0, bytes); +} + +static void +rtems_rtl_unresolved_compact (void) +{ + rtems_rtl_unresolved_t* unresolved = rtems_rtl_unresolved (); + if (unresolved) + { + /* + * Iterate backwards over the blocks removing any used records. A block is + * compacted moving up the block. + */ + rtems_chain_node* node = rtems_chain_last (&unresolved->blocks); + while (!rtems_chain_is_head (&unresolved->blocks, node)) + { + rtems_chain_node* prev = rtems_chain_previous (node); + rtems_rtl_unresolv_block_t* block = (rtems_rtl_unresolv_block_t*) node; + rtems_rtl_unresolv_rec_t* rec = rtems_rtl_unresolved_rec_first (block); + + while (!rtems_rtl_unresolved_rec_is_last (block, rec)) + { + bool next = true; + + if (rec->type == rtems_rtl_unresolved_name) + { + if (rec->rec.name.refs == 0) + { + size_t name_recs = rtems_rtl_unresolved_name_recs (rec->rec.name.name); + rtems_rtl_unresolved_clean_block (block, rec, name_recs, + unresolved->block_recs); + next = false; + } + } + else if (rec->type == rtems_rtl_unresolved_reloc) + { + if (!rec->rec.reloc.obj) + { + rtems_rtl_unresolved_clean_block (block, rec, 1, + unresolved->block_recs); + next = false; + } + } + + if (next) + rec = rtems_rtl_unresolved_rec_next (rec); + } + + if (block->recs == 0) + { + rtems_chain_extract (node); + free (block); + } + + node = prev; + } + } +} + +bool +rtems_rtl_unresolved_table_open (rtems_rtl_unresolved_t* unresolved, + size_t block_recs) +{ + unresolved->marker = 0xdeadf00d; + unresolved->block_recs = block_recs; + rtems_chain_initialize_empty (&unresolved->blocks); + return true; +} + +void +rtems_rtl_unresolved_table_close (rtems_rtl_unresolved_t* unresolved) +{ + rtems_chain_node* node = rtems_chain_first (&unresolved->blocks); + while (!rtems_chain_is_tail (&unresolved->blocks, node)) + { + rtems_chain_node* next = rtems_chain_next (node); + free (node); + node = next; + } +} + +bool +rtems_rtl_unresolved_interate (rtems_rtl_unresolved_iterator_t iterator, + void* data) +{ + rtems_rtl_unresolved_t* unresolved = rtems_rtl_unresolved (); + if (unresolved) + { + rtems_chain_node* node = rtems_chain_first (&unresolved->blocks); + while (!rtems_chain_is_tail (&unresolved->blocks, node)) + { + rtems_rtl_unresolv_block_t* block = (rtems_rtl_unresolv_block_t*) node; + rtems_rtl_unresolv_rec_t* rec = rtems_rtl_unresolved_rec_first (block); + + while (!rtems_rtl_unresolved_rec_is_last (block, rec)) + { + if (iterator (rec, data)) + return true; + rec = rtems_rtl_unresolved_rec_next (rec); + } + + node = rtems_chain_next (node); + } + } + return false; +} + +bool +rtems_rtl_unresolved_add (rtems_rtl_obj_t* obj, + const uint16_t flags, + const char* name, + const uint16_t sect, + const rtems_rtl_word_t* rel) +{ + rtems_rtl_unresolved_t* unresolved; + rtems_chain_node* node; + rtems_rtl_unresolv_block_t* block; + rtems_rtl_unresolv_rec_t* rec; + int name_index; + size_t name_recs; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) + printf ("rtl: unresolv: add: %s(s:%d) -> %s\n", + rtems_rtl_obj_oname (obj), sect, name); + + unresolved = rtems_rtl_unresolved (); + if (!unresolved) + return false; + + /* + * Find the first block with a spare record. + */ + node = rtems_chain_first (&unresolved->blocks); + block = NULL; + while (!rtems_chain_is_tail (&unresolved->blocks, node)) + { + block = (rtems_rtl_unresolv_block_t*) node; + if (block->recs < unresolved->block_recs) + break; + block = NULL; + node = rtems_chain_next (node); + } + + /* + * No blocks with any spare records, allocate a new block. + */ + if (!block) + { + block = rtems_rtl_unresolved_block_alloc (unresolved); + if (!block) + return false; + } + + name_index = rtems_rtl_unresolved_find_name (unresolved, name, true); + name_recs = rtems_rtl_unresolved_name_recs (name); + + /* + * An index less than 0 means the name is present and "0 - index" is the next + * index to use. + */ + if (name_index < 0) + { + rtems_rtl_unresolv_block_t* name_block = block; + + /* + * Is there enough room to fit the name ? It not add a new block. + */ + if (name_recs > (unresolved->block_recs - block->recs)) + { + name_block = rtems_rtl_unresolved_block_alloc (unresolved); + if (!name_block) + return false; + } + + rec = rtems_rtl_unresolved_rec_first_free (name_block); + rec->type = rtems_rtl_unresolved_name; + rec->rec.name.refs = 1; + rec->rec.name.length = strlen (name) + 1; + memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length + 1); + block->recs += name_recs; + name_index = 0 - name_index; + + /* + * If the name block is the reloc block and it is full allocate a new + * block for the relocation record. + */ + if ((block == name_block) && (block->recs >= unresolved->block_recs)) + { + block = rtems_rtl_unresolved_block_alloc (unresolved); + if (!block) + return false; + } + } + + rec = rtems_rtl_unresolved_rec_first_free (block); + rec->type = rtems_rtl_unresolved_reloc; + rec->rec.reloc.obj = obj; + rec->rec.reloc.flags = flags; + rec->rec.reloc.name = name_index; + rec->rec.reloc.sect = sect; + rec->rec.reloc.rel[0] = rel[0]; + rec->rec.reloc.rel[1] = rel[1]; + rec->rec.reloc.rel[2] = rel[2]; + + ++block->recs; + + return true; +} + +void +rtems_rtl_unresolved_resolve (void) +{ + rtems_rtl_unresolved_reloc_data_t rd; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) + printf ("rtl: unresolv: global resolve\n"); + rd.name = 0; + rd.name_rec = NULL; + rd.sym = NULL; + rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_iterator, &rd); + rtems_rtl_unresolved_compact (); +} + +bool +rtems_rtl_unresolved_remove (rtems_rtl_obj_t* obj, + const char* name, + const uint16_t sect, + const rtems_rtl_word_t* rel) +{ + rtems_rtl_unresolved_t* unresolved; + unresolved = rtems_rtl_unresolved (); + if (!unresolved) + return false; + return false; +} + diff --git a/cpukit/libdl/rtl-unresolved.h b/cpukit/libdl/rtl-unresolved.h new file mode 100644 index 0000000000..5cc51620df --- /dev/null +++ b/cpukit/libdl/rtl-unresolved.h @@ -0,0 +1,212 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object File Unresolved Relocations Table. + * + * The unresolved relocation table holds relocations in a loaded object file + * which reference unresolved external symbols. The support is needed to allow + * dependent object files to load. In the case of dependent object files one + * will have unresolved externals until the dependent object file is also + * loaded. There is no load order that resolves this. + * + * The unresolved relocation table is a single table used by all object files + * with unresolved symbols. It made of blocks linked together where blocks are + * allocated as requiered. The table is always maintained compacted. That is as + * relocations are resolved and removed the table is compacted. The only + * pointer in the table is the object file poniter. This is used to identify + * which object the relocation belongs to. There are no linking or back + * pointers in the unresolved relocations table. The table is scanned for each + * object file's relocations. This is not fast but the table should be small + * and if it happens to grow large you have other more pressing issues to + * resolve in your application. + * + * The table holds two (2) types of records: + * + * # Symbol name strings. + * # Relocations. + * + * The symbol name a relocation references is held in a specific symbol name + * string record in the table the relocation record references. The record + * counts the number of references and the string is removed from the table + * when the reference count reaches 0. There can be many relocations + * referencing the symbol. The strings are referenced by a single 16bit + * unsigned integer which is the count of the string in the table. + * + * The section the relocation is for in the object is the section number. The + * relocation data is series of machine word sized fields: + * + * # Offset in the section. + * # Relocation info (format specific) + * # Additional format specific data. + */ + +#if !defined (_RTEMS_RTL_UNRESOLVED_H_) +#define _RTEMS_RTL_UNRESOLVED_H_ + +#include <rtems.h> +#include "rtl-obj-fwd.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Hack to work around machine size. This needs to be cleaned up + * to better support 64bit targets. + */ +typedef uint32_t rtems_rtl_word_t; + +/** + * The types of records in the blocks. + */ +typedef enum rtems_rtl_unresolved_rtype_e +{ + rtems_rtl_unresolved_empty = 0, /**< The records is empty. Must always be 0 */ + rtems_rtl_unresolved_name = 1, /**< The record is a name. */ + rtems_rtl_unresolved_reloc = 2 /**< The record is a relocation record. */ +} rtems_rtl_unresolved_rtype_t; + +/** + * Unresolved externals symbol names. The names are reference counted and + * separate from the relocation records because a number of records could + * reference the same symbol name. + */ +typedef struct rtems_rtl_unresolv_name_s +{ + uint16_t refs; /**< The number of references to this name. */ + uint16_t length; /**< The length of this name. */ + const char name[12]; /**< The symbol name. */ +} rtems_rtl_unresolv_name_t; + +/** + * Unresolved externals symbols require the relocation records to be held + * and references. + */ +typedef struct rtems_rtl_unresolv_reloc_s +{ + rtems_rtl_obj_t* obj; /**< The relocation's object file. */ + uint16_t flags; /**< Format specific flags. */ + uint16_t name; /**< The symbol's name. */ + uint16_t sect; /**< The target section. */ + rtems_rtl_word_t rel[3]; /**< Relocation record. */ +} rtems_rtl_unresolv_reloc_t; + +/** + * Unresolved externals records. + */ +typedef struct rtems_rtl_unresolv_rec_s +{ + rtems_rtl_unresolved_rtype_t type; + union + { + rtems_rtl_unresolv_name_t name; /**< The name, or */ + rtems_rtl_unresolv_reloc_t reloc; /**< the relocation record. */ + } rec; +} rtems_rtl_unresolv_rec_t; + +/** + * Unresolved blocks. + */ +typedef struct rtems_rtl_unresolv_block_s +{ + rtems_chain_node link; /**< Blocks are chained. */ + uint32_t recs; /**< The number of records in the block. */ + rtems_rtl_unresolv_rec_t rec; /**< The records. More follow. */ +} rtems_rtl_unresolv_block_t; + +/** + * Unresolved table holds the names and relocations. + */ +typedef struct rtems_rtl_unresolved_s +{ + uint32_t marker; + size_t block_recs; /**< The records per blocks allocated. */ + rtems_chain_control blocks; /**< List of blocks. */ +} rtems_rtl_unresolved_t; + +/** + * The iterator function used to iterate over the unresolved table. + * + * @param rec The current iterator. + * @param data The user data. + * @retval true The iterator has finished. + * @retval false The iterator has not finished. Keep iterating. + */ +typedef bool rtems_rtl_unresolved_iterator_t (rtems_rtl_unresolv_rec_t* rec, + void* data); + +/** + * Open an unresolved relocation table. + * + * @param unresolv The unresolved table to open. + * @param block_records The number of records per block allocated. + * @retval true The table is open. + * @retval false The unresolved relocation table could not created. The RTL + * error has the error. + */ +bool rtems_rtl_unresolved_table_open (rtems_rtl_unresolved_t* unresolved, + size_t block_records); + +/** + * Close the table and erase the blocks. + * + * @param unreolved Close the unresolved table. + */ +void rtems_rtl_unresolved_table_close (rtems_rtl_unresolved_t* unresolved); + +/** + * Iterate over the table of unresolved entries. + */ +bool rtems_rtl_unresolved_interate (rtems_rtl_unresolved_iterator_t iterator, + void* data); + +/** + * Add a relocation to the list of unresolved relocations. + * + * @param unresolved The unresolved symbol table. + * @param obj The object table the symbols are for. + * @param flags Format specific flags. + * @param name The symbol name the relocation references. + * @param sect The target section number the relocation references. + * @param rel The format specific relocation data. + * @retval true The relocation has been added. + * @retval false The relocation could not be added. + */ +bool rtems_rtl_unresolved_add (rtems_rtl_obj_t* obj, + const uint16_t flags, + const char* name, + const uint16_t sect, + const rtems_rtl_word_t* rel); + +/** + * Resolve the unresolved symbols. + */ +void rtems_rtl_unresolved_resolve (void); + +/** + * Remove a relocation from the list of unresolved relocations. + * + * @param unresolved The unresolved symbol table. + * @param obj The object table the symbols are for. + * @param esyms The exported symbol table. + * @param size The size of the table in bytes. + */ +bool rtems_rtl_unresolved_remove (rtems_rtl_obj_t* obj, + const char* name, + const uint16_t sect, + const rtems_rtl_word_t* rel); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c new file mode 100644 index 0000000000..c55cd94084 --- /dev/null +++ b/cpukit/libdl/rtl.c @@ -0,0 +1,637 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor + * + * This is the RTL implementation. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <rtems/libio_.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-allocator.h" +#include "rtl-error.h" +#include "rtl-string.h" +#include "rtl-trace.h" + +/** + * Semaphore configuration to create a mutex. + */ +#define RTEMS_MUTEX_ATTRIBS \ + (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \ + RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL) + +/** + * Symbol table cache size. They can be big so the cache needs space to work. + */ +#define RTEMS_RTL_ELF_SYMBOL_CACHE (2048) + +/** + * String table cache size. + */ +#define RTEMS_RTL_ELF_STRING_CACHE (2048) + +/** + * Relocations table cache size. + */ +#define RTEMS_RTL_ELF_RELOC_CACHE (2048) + +/** + * Decompression output buffer. + */ +#define RTEMS_RTL_COMP_OUTPUT (2048) + +/** + * Static RTL data is returned to the user when the linker is locked. + */ +static rtems_rtl_data_t* rtl; + +/** + * Define a default base global symbol loader function that is weak + * so a real table can be linked in when the user wants one. + */ +void rtems_rtl_base_global_syms_init (void) __attribute__ ((weak)); +void +rtems_rtl_base_global_syms_init (void) +{ + /* + * Do nothing. + */ +} + +static bool +rtems_rtl_data_init (void) +{ + /* + * Lock the RTL. We only create a lock if a call is made. First we test if a + * lock is present. If one is present we lock it. If not the libio lock is + * locked and we then test the lock again. If not present we create the lock + * then release libio lock. + */ + if (!rtl) + { + rtems_libio_lock (); + + if (!rtl) + { + rtems_status_code sc; + rtems_id lock; + + /* + * Always in the heap. + */ + rtl = malloc (sizeof (rtems_rtl_data_t)); + if (!rtl) + { + errno = ENOMEM; + return false; + } + + *rtl = (rtems_rtl_data_t) { 0 }; + + /* + * The initialise the allocator data. + */ + rtems_rtl_alloc_initialise (&rtl->allocator); + + /* + * Create the RTL lock. + */ + sc = rtems_semaphore_create (rtems_build_name ('R', 'T', 'L', 'D'), + 1, RTEMS_MUTEX_ATTRIBS, + RTEMS_NO_PRIORITY, &lock); + if (sc != RTEMS_SUCCESSFUL) + { + free (rtl); + return false; + } + + sc = rtems_semaphore_obtain (lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + { + rtems_semaphore_delete (lock); + free (rtl); + return false; + } + + rtl->lock = lock; + + /* + * Initialise the objects list and create any required services. + */ + rtems_chain_initialize_empty (&rtl->objects); + + if (!rtems_rtl_symbol_table_open (&rtl->globals, + RTEMS_RTL_SYMS_GLOBAL_BUCKETS)) + { + rtems_semaphore_delete (lock); + free (rtl); + return false; + } + + if (!rtems_rtl_unresolved_table_open (&rtl->unresolved, + RTEMS_RTL_UNRESOLVED_BLOCK_SIZE)) + { + rtems_rtl_symbol_table_close (&rtl->globals); + rtems_semaphore_delete (lock); + free (rtl); + return false; + } + + if (!rtems_rtl_obj_cache_open (&rtl->symbols, + RTEMS_RTL_ELF_SYMBOL_CACHE)) + { + rtems_rtl_symbol_table_close (&rtl->globals); + rtems_rtl_unresolved_table_close (&rtl->unresolved); + rtems_semaphore_delete (lock); + free (rtl); + return false; + } + + if (!rtems_rtl_obj_cache_open (&rtl->strings, + RTEMS_RTL_ELF_STRING_CACHE)) + { + rtems_rtl_obj_cache_close (&rtl->symbols); + rtems_rtl_unresolved_table_close (&rtl->unresolved); + rtems_rtl_symbol_table_close (&rtl->globals); + rtems_semaphore_delete (lock); + free (rtl); + return false; + } + + if (!rtems_rtl_obj_cache_open (&rtl->relocs, + RTEMS_RTL_ELF_RELOC_CACHE)) + { + rtems_rtl_obj_cache_close (&rtl->strings); + rtems_rtl_obj_cache_close (&rtl->symbols); + rtems_rtl_unresolved_table_close (&rtl->unresolved); + rtems_rtl_symbol_table_close (&rtl->globals); + rtems_semaphore_delete (lock); + free (rtl); + return false; + } + + if (!rtems_rtl_obj_comp_open (&rtl->decomp, + RTEMS_RTL_COMP_OUTPUT)) + { + rtems_rtl_obj_cache_close (&rtl->relocs); + rtems_rtl_obj_cache_close (&rtl->strings); + rtems_rtl_obj_cache_close (&rtl->symbols); + rtems_rtl_unresolved_table_close (&rtl->unresolved); + rtems_rtl_symbol_table_close (&rtl->globals); + rtems_semaphore_delete (lock); + free (rtl); + return false; + } + + rtl->base = rtems_rtl_obj_alloc (); + if (!rtl->base) + { + rtems_rtl_obj_comp_close (&rtl->decomp); + rtems_rtl_obj_cache_close (&rtl->relocs); + rtems_rtl_obj_cache_close (&rtl->strings); + rtems_rtl_obj_cache_close (&rtl->symbols); + rtems_rtl_unresolved_table_close (&rtl->unresolved); + rtems_rtl_symbol_table_close (&rtl->globals); + rtems_semaphore_delete (lock); + free (rtl); + return false; + } + + /* + * Need to malloc the memory so the free does not complain. + */ + rtl->base->oname = rtems_rtl_strdup ("rtems-kernel"); + + rtems_chain_append (&rtl->objects, &rtl->base->link); + } + + rtems_libio_unlock (); + + rtems_rtl_path_append ("."); + + rtems_rtl_base_global_syms_init (); + + rtems_rtl_unlock (); + } + return true; +} + +rtems_rtl_data_t* +rtems_rtl_data (void) +{ + return rtl; +} + +rtems_rtl_symbols_t* +rtems_rtl_global_symbols (void) +{ + if (!rtl) + { + rtems_rtl_set_error (ENOENT, "no rtl"); + return NULL; + } + return &rtl->globals; +} + +rtems_rtl_unresolved_t* +rtems_rtl_unresolved (void) +{ + if (!rtl) + { + rtems_rtl_set_error (ENOENT, "no rtl"); + return NULL; + } + return &rtl->unresolved; +} + +void +rtems_rtl_obj_caches (rtems_rtl_obj_cache_t** symbols, + rtems_rtl_obj_cache_t** strings, + rtems_rtl_obj_cache_t** relocs) +{ + if (!rtl) + { + if (symbols) + *symbols = NULL; + if (strings) + *strings = NULL; + if (relocs) + *relocs = NULL; + } + else + { + if (symbols) + *symbols = &rtl->symbols; + if (strings) + *strings = &rtl->strings; + if (relocs) + *relocs = &rtl->relocs; + } +} + +void +rtems_rtl_obj_caches_flush () +{ + if (rtl) + { + rtems_rtl_obj_cache_flush (&rtl->symbols); + rtems_rtl_obj_cache_flush (&rtl->strings); + rtems_rtl_obj_cache_flush (&rtl->relocs); + } +} + +void +rtems_rtl_obj_comp (rtems_rtl_obj_comp_t** decomp, + rtems_rtl_obj_cache_t* cache, + int fd, + int compression, + off_t offset) +{ + if (!rtl) + { + *decomp = NULL; + } + else + { + *decomp = &rtl->decomp; + rtems_rtl_obj_comp_set (*decomp, cache, fd, compression, offset); + } +} + +rtems_rtl_data_t* +rtems_rtl_lock (void) +{ + rtems_status_code sc; + + if (!rtems_rtl_data_init ()) + return NULL; + + sc = rtems_semaphore_obtain (rtl->lock, + RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + { + errno = EINVAL; + return NULL; + } + + return rtl; +} + +bool +rtems_rtl_unlock (void) +{ + /* + * Not sure any error should be returned or an assert. + */ + rtems_status_code sc; + sc = rtems_semaphore_release (rtl->lock); + if ((sc != RTEMS_SUCCESSFUL) && (errno == 0)) + { + errno = EINVAL; + return false; + } + return true; +} + +rtems_rtl_obj_t* +rtems_rtl_check_handle (void* handle) +{ + rtems_rtl_obj_t* obj; + rtems_chain_node* node; + + obj = handle; + node = rtems_chain_first (&rtl->objects); + + while (!rtems_chain_is_tail (&rtl->objects, node)) + { + rtems_rtl_obj_t* check = (rtems_rtl_obj_t*) node; + if (check == obj) + return obj; + node = rtems_chain_next (node); + } + + return NULL; +} + +rtems_rtl_obj_t* +rtems_rtl_find_obj (const char* name) +{ + rtems_chain_node* node; + rtems_rtl_obj_t* found = NULL; + const char* aname = NULL; + const char* oname = NULL; + off_t ooffset; + + if (!rtems_rtl_parse_name (name, &aname, &oname, &ooffset)) + return NULL; + + node = rtems_chain_first (&rtl->objects); + + while (!rtems_chain_is_tail (&rtl->objects, node)) + { + rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) node; + if ((aname == NULL && strcmp (obj->oname, oname) == 0) || + (aname != NULL && + strcmp (obj->aname, aname) == 0 && strcmp (obj->oname, oname) == 0)) + { + found = obj; + break; + } + node = rtems_chain_next (node); + } + + if (!aname) + rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) aname); + + if (!oname) + rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) oname); + + return found; +} + +rtems_rtl_obj_t* +rtems_rtl_load_object (const char* name, int mode) +{ + rtems_rtl_obj_t* obj; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: loading '%s'\n", name); + + /* + * See if the object module has already been loaded. + */ + obj = rtems_rtl_find_obj (name); + if (!obj) + { + /* + * Allocate a new object file descriptor and attempt to load it. + */ + obj = rtems_rtl_obj_alloc (); + if (obj == NULL) + { + rtems_rtl_set_error (ENOMEM, "no memory for object descriptor"); + return NULL; + } + + /* + * Find the file in the file system using the search path. The fname field + * will point to a valid file name if found. + */ + if (!rtems_rtl_obj_find_file (obj, name)) + { + rtems_rtl_obj_free (obj); + return NULL; + } + + rtems_chain_append (&rtl->objects, &obj->link); + + if (!rtems_rtl_obj_load (obj)) + { + rtems_rtl_obj_free (obj); + return NULL; + } + + rtems_rtl_unresolved_resolve (); + } + + /* + * Increase the number of users. + */ + ++obj->users; + + /* + * FIXME: Resolving existing unresolved symbols could add more constructors + * lists that need to be called. Make a list in the obj load layer and + * invoke the list here. + */ + + /* + * Run any local constructors if this is the first user because the object + * file will have just been loaded. Unlock the linker to avoid any dead locks + * if the object file needs to load files or update the symbol table. We also + * do not want a constructor to unload this object file. + */ + if (obj->users == 1) + { + obj->flags |= RTEMS_RTL_OBJ_LOCKED; + rtems_rtl_unlock (); + rtems_rtl_obj_run_ctors (obj); + rtems_rtl_lock (); + obj->flags &= ~RTEMS_RTL_OBJ_LOCKED; + } + + return obj; +} + +bool +rtems_rtl_unload_object (rtems_rtl_obj_t* obj) +{ + bool ok = true; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD)) + printf ("rtl: unloading '%s'\n", rtems_rtl_obj_fname (obj)); + + /* + * If the object is locked it cannot be unloaded and the unload fails. + */ + if ((obj->flags & RTEMS_RTL_OBJ_LOCKED) == RTEMS_RTL_OBJ_LOCKED) + { + rtems_rtl_set_error (EINVAL, "cannot unload when locked"); + return false; + } + + /* + * Check the number of users in a safe manner. If this is the last user unload the + * object file from memory. + */ + if (obj->users > 0) + --obj->users; + + if (obj->users == 0) + { + obj->flags |= RTEMS_RTL_OBJ_LOCKED; + rtems_rtl_unlock (); + rtems_rtl_obj_run_dtors (obj); + rtems_rtl_lock (); + obj->flags &= ~RTEMS_RTL_OBJ_LOCKED; + + ok = rtems_rtl_obj_unload (obj); + } + + return ok; +} + +void +rtems_rtl_run_ctors (rtems_rtl_obj_t* obj) +{ + rtems_rtl_obj_run_ctors (obj); +} + +static bool +rtems_rtl_path_update (bool prepend, const char* path) +{ + char* paths; + const char* src = NULL; + char* dst; + int len; + + if (!rtems_rtl_lock ()) + return false; + + len = strlen (path); + + if (rtl->paths) + len += strlen (rtl->paths) + 1; + else + prepend = true; + + paths = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, false); + + if (!paths) + { + rtems_rtl_unlock (); + return false; + } + + dst = paths; + + if (prepend) + { + len = strlen (path); + src = path; + } + else if (rtl->paths) + { + len = strlen (rtl->paths); + src = rtl->paths; + } + + memcpy (dst, src, len); + + dst += len; + + if (rtl->paths) + { + *dst = ':'; + ++dst; + } + + if (prepend) + { + src = rtl->paths; + if (src) + len = strlen (src); + } + else + { + len = strlen (path); + src = path; + } + + if (src) + { + memcpy (dst, src, len); + dst += len; + } + + *dst = '\0'; + + rtl->paths = paths; + + rtems_rtl_unlock (); + return false; +} + +bool +rtems_rtl_path_append (const char* path) +{ + return rtems_rtl_path_update (false, path); +} + +bool +rtems_rtl_path_prepend (const char* path) +{ + return rtems_rtl_path_update (true, path); +} + +void +rtems_rtl_base_sym_global_add (const unsigned char* esyms, + unsigned int size) +{ + if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) + printf ("rtl: adding global symbols, table size %u\n", size); + + if (!rtems_rtl_lock ()) + { + rtems_rtl_set_error (EINVAL, "global add cannot lock rtl"); + return; + } + + rtems_rtl_symbol_global_add (rtl->base, esyms, size); + + rtems_rtl_unlock (); +} + +rtems_rtl_obj_t* +rtems_rtl_baseimage (void) +{ + return NULL; +} diff --git a/cpukit/libdl/rtl.h b/cpukit/libdl/rtl.h new file mode 100644 index 0000000000..d0a0d0085c --- /dev/null +++ b/cpukit/libdl/rtl.h @@ -0,0 +1,320 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker + * + * This is the POSIX interface to run-time loading of code into RTEMS. + */ + +#if !defined (_RTEMS_RTL_H_) +#define _RTEMS_RTL_H_ + +#include <link.h> +#include <rtems.h> +#include <rtems/chain.h> + +#include <rtems/rtl/rtl-allocator.h> +#include <rtems/rtl/rtl-fwd.h> +#include <rtems/rtl/rtl-obj.h> +#include <rtems/rtl/rtl-obj-cache.h> +#include <rtems/rtl/rtl-obj-comp.h> +#include <rtems/rtl/rtl-unresolved.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup rtems_rtl RTEMS Runtime Link Editor + * + * The module implements a runtime link editor with the standard dlopen, and + * dlclose family of functions. + * + * The runtime link editor is different to that found on Unix type systems. The + * object modules are compiled for PIC or position indepentent code and + * therefore require relocating when loaded. + * + * The object file format is currently ELF and object files can be separate + * files or in an archive. Object files in an archive are referenced by + * specifing 'archive:object' format. For example 'libfoo.a:bar.o'. + */ + +/** + * Macros to glue two tokens. + */ +#ifdef __STDC__ +#define RTL_XGLUE(a,b) a##b +#else +#define RTL_XGLUE(a,b) a/**/b +#endif + +#define RTL_GLUE(a,b) RTL_XGLUE(a,b) + +/** + * The number of buckets in the global symbol table. + */ +#define RTEMS_RTL_SYMS_GLOBAL_BUCKETS (32) + +/** + * The number of relocation record per block in the unresolved table. + */ +#define RTEMS_RTL_UNRESOLVED_BLOCK_SIZE (64) + +/** + * The global debugger interface variable. + */ +extern struct r_debug _rtld_debug; + +/** + * Debugger break function. Call when debugging to have it read the _rtld_debug + * variable. + */ +extern void _rtld_debug_state (void); + +/** + * The type of constructor/destructor function. + */ +typedef void (*rtems_rtl_cdtor_t)(void); + +/** + * The global RTL data. This structure is allocated on the heap when the first + * call to the RTL is made and never released. + * + * The global symbol table is a hash table held in this structure and the + * actual symbols are part of the object's structure. If this is a problem we + * could look at a hash table per object file. + */ +struct rtems_rtl_data_s +{ + rtems_id lock; /**< The RTL lock id */ + rtems_rtl_alloc_data_t allocator; /**< The allocator data. */ + rtems_chain_control objects; /**< List if loaded object files. */ + const char* paths; /**< Search paths for archives. */ + rtems_rtl_symbols_t globals; /**< Global symbol table. */ + rtems_rtl_unresolved_t unresolved; /**< Unresolved symbols. */ + rtems_rtl_obj_t* base; /**< Base object file. */ + rtems_rtl_obj_cache_t symbols; /**< Symbols object file cache. */ + rtems_rtl_obj_cache_t strings; /**< Strings object file cache. */ + rtems_rtl_obj_cache_t relocs; /**< Relocations object file cache. */ + rtems_rtl_obj_comp_t decomp; /**< The decompression compressor. */ + int last_errno; /**< Last error number. */ + char last_error[64]; /**< Last error string. */ +}; + +/** + * Get the RTL data with out locking. This call assmes the RTL is locked. + * + * @return rtems_rtl_data_t* The RTL data after being locked. + * @retval NULL The RTL data is not initialised. + */ +rtems_rtl_data_t* rtems_rtl_data (void); + +/** + * Get the RTL global symbol table with out locking. This call assmes the RTL + * is locked. + * + * @return rtems_rtl_symbols_t* The RTL global symbols after being locked. + * @retval NULL The RTL data is not initialised. + */ +rtems_rtl_symbols_t* rtems_rtl_global_symbols (void); + +/** + * Get the RTL resolved table with out locking. This call assmes the RTL + * is locked. + * + * @return rtems_rtl_unresolv_t* The RTL unresolved symbols and reloc records. + * @retval NULL The RTL data is not initialised. + */ +rtems_rtl_unresolved_t* rtems_rtl_unresolved (void); + +/** + * Get the RTL symbols, strings, or relocations object file caches. This call + * assmes the RTL is locked. + * + * @param symbols Pointer to the location to set the cache into. Returns NULL + * is rtl is not initialised. If NULL is passed in no value set. + * @param strings Pointer to the location to set the cache into. Returns NULL + * is rtl is not initialised. If NULL is passed in no value set. + * @param relocs Pointer to the location to set the cache into. Returns NULL + * is rtl is not initialised. If NULL is passed in no value set. + */ +void rtems_rtl_obj_caches (rtems_rtl_obj_cache_t** symbols, + rtems_rtl_obj_cache_t** strings, + rtems_rtl_obj_cache_t** relocs); + +/** + * Flush all the object file caches. + */ +void rtems_rtl_obj_caches_flush (void); + +/** + * Get the RTL decompressor setting the cache and the offset in the file the + * compressed stream starts. This call assmes the RTL is locked. + * + * @param decomp Pointer to the location to set the compressor into. Returns + * NULL is rtl is not initialised. + * @param cache The cache to read the file with. Saves needing an extrs buffer. + * @param offset The offset in the file the compressed stream starts. + */ +void rtems_rtl_obj_comp (rtems_rtl_obj_comp_t** decomp, + rtems_rtl_obj_cache_t* cache, + int fd, + int compression, + off_t offset); + +/** + * Lock the Run-time Linker. + * + * @return rtems_rtl_data_t* The RTL data after being locked. + * @retval NULL The RTL data could not be initialised or locked. Typically this + * means the lock could not be created. + */ +rtems_rtl_data_t* rtems_rtl_lock (void); + +/** + * Unlock the Run-time Linker. + * + * @return True The RTL is unlocked. + * @return False The RTL could not be unlocked. Not much you can do. + */ +bool rtems_rtl_unlock (void); + +/** + * Check a pointer is a valid object file descriptor returning the pointer as + * that type. + * + * Assumes the RTL has been locked. + * + * @param handle Pointer to the object file to be validated. + * @return rtl_obj* The object file descriptor. NULL is returned if invalid. + */ +rtems_rtl_obj_t* rtems_rtl_check_handle (void* handle); + +/** + * Find the object given a file name. + * + * @param name The name of the object file. + * @retval NULL No object file with that name found. + * @return rtems_rtl_obj_t* The object file descriptor. + */ +rtems_rtl_obj_t* rtems_rtl_find_obj (const char* name); + +/** + * Load an object file into memory relocating it. It will not be resolved + * against other symbols in other object files or the base image. + * + * The name can be a file name for an object file or it can be encoded to + * reference an archive of object modules (static library). This encoding is + * specific to RTEMS and allows dependences to specify an archive without the + * searching overhead normally incurred by linkers locating object files in an + * archive. The file name format rules are: + * + * 1. Absolute file references a specific object file in the architecture + * specific location on the file system. + * + * 2. Relative file references an object format file in the search path. + * + * 3. Absolute archive and file reference to a specific location in the file + * system. The archive and file are encoded as 'archive:file [@offset]' + * where 'archive' is a valid file at the absolute path in the file system, + * and 'file' is a contained in the archive, and optionally an offset to + * the 'file' in the 'archive'. If no offset is provided the archive is + * searched. + * + * 4. Relative archive and file in the search path. The encoding is the same + * as described in item 3 of this list. + * + * Assumes the RTL has been locked. + * + * @param name The name of the object file. + * @param mode The mode of the load as defined by the dlopen call. + * @return rtl_obj* The object file descriptor. NULL is returned if the load fails. + */ +rtems_rtl_obj_t* rtems_rtl_load_object (const char* name, int mode); + +/** + * Unload an object file. This only happens when the user count is 0. + * + * Assumes the RTL has been locked. + * + * @param obj The object file descriptor. + * @retval true The object file has been unloaded. + * @retval false The object file could not be unloaded. + */ +bool rtems_rtl_unload_object (rtems_rtl_obj_t* obj); + +/** + * Run any constructor functions the object file may contain. This call + * assumes the linker is unlocked. + * + * @param obj The object file. + */ +void rtems_rtl_run_ctors (rtems_rtl_obj_t* obj); + +/** + * Get the last error message clearing it. This operation locks the run time + * linker and therefore keeps the RTL thread safe but this call is not thread + * safe is multiple threads are loading object files at the same time. This + * call is provided to map to the dlopen family of calls. + * + * @param message Pointer to a buffer to copy the message into. + * @param max_message The maximum message that can be copied. + * @return int The last error number. + */ +int rtems_rtl_get_error (char* message, size_t max_message); + +/** + * Append the path to the search path. + * + * @path The path to append. + * @retval false The path could not be appended. + * @retval true The path was appended. + */ +bool rtems_rtl_path_append (const char* path); + +/** + * Prepend the path to the search path. + * + * @path The path to prepend. + * @retval false The path could not be prepended. + * @retval true The path was prepended. + */ + +bool rtems_rtl_path_prepend (const char* path); + +/** + * Add an exported symbol table to the global symbol table. This call is + * normally used by an object file when loaded that contains a global symbol + * table. + * + * @param esyms The exported symbol table. + * @param count The size of the exported symbol table. + */ +void rtems_rtl_base_sym_global_add (const unsigned char* esyms, + unsigned int count); + +/** + * Return the object file descriptor for the base image. The object file + * descriptor returned is created when the run time linker is initialised. + * + * Assumes the RTL has been locked. + * + * @return rtl_obj* The object file descriptor for the base image. NULL is + * returned if the load fails. + */ +rtems_rtl_obj_t* rtems_rtl_baseimage (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif |