cpukit: Add libdl with the Runtime Loader (RTL) code.

This is a merge of the RTL project.
This commit is contained in:
Chris Johns
2014-10-26 18:09:41 -07:00
parent 513668f6f1
commit ae5fe7e6bc
91 changed files with 14746 additions and 5 deletions

View File

@@ -11,6 +11,7 @@ SUBDIRS += libi2c
SUBDIRS += libmisc
SUBDIRS += libmd
SUBDIRS += libgnat
SUBDIRS += libdl
SUBDIRS += wrapup
SUBDIRS += zlib
@@ -41,7 +42,6 @@ include_uuid_HEADERS = libmisc/uuid/uuid.h
include_utf8procdir = $(includedir)/utf8proc
include_utf8proc_HEADERS = libmisc/utf8proc/utf8proc.h
if NEWLIB
include_sysdir = $(includedir)/sys
include_sys_HEADERS =
@@ -69,6 +69,24 @@ include_rtems_bsdnetdir = $(includedir)/rtems/bsdnet
include_rtems_bsdnet_HEADERS = libnetworking/rtems/bsdnet/servers.h
include_rtems_bsdnet_HEADERS += libnetworking/rtems/bsdnet/_types.h
endif
if LIBDL
include_HEADERS += libdl/dlfcn.h
include_HEADERS += libdl/include/link.h
include_HEADERS += libdl/include/link_elf.h
include_sys_HEADERS += libdl/include/sys/cdefs_elf.h
include_sys_HEADERS += libdl/include/sys/exec_elf.h
include_arch_machinedir = $(includedir)/machine
include_arch_machine_HEADERS =
include_arch_machine_HEADERS += libdl/include/arch/@RTEMS_CPU@/machine/elf_machdep.h
include_rtems_rtldir = $(includedir)/rtems/rtl
include_rtems_rtl_HEADERS =
include_rtems_rtl_HEADERS += libdl/dlfcn-shell.h
include_rtems_rtl_HEADERS += libdl/rtl.h libdl/rtl-allocator.h libdl/rtl-obj-fwd.h
include_rtems_rtl_HEADERS += libdl/rtl-fwd.h libdl/rtl-obj.h libdl/rtl-obj-cache.h
include_rtems_rtl_HEADERS += libdl/rtl-obj-comp.h libdl/rtl-unresolved.h
include_rtems_rtl_HEADERS += libdl/rtl-indirect-ptr.h libdl/rtl-sym.h
include_rtems_rtl_HEADERS += libdl/rap.h libdl/rap-shell.h
endif
include_rtems_HEADERS += include/rtems/bspIo.h

View File

@@ -298,7 +298,7 @@ AC_ENABLE_MULTILIB([Makefile],[..])
AC_MSG_CHECKING([for assignable stdio])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[#include <stdio.h>],
[#include <stdio.h>],
[stdin = fopen("/tmp", "r")])],
[HAVE_ASSIGNABLE_STDIO=yes],
[HAVE_ASSIGNABLE_STDIO=no])
@@ -322,7 +322,7 @@ AC_CHECK_SIZEOF([time_t])
AC_CHECK_SIZEOF([size_t])
# FIXME: Mandatory in SUSv4, optional in SUSv3.
# FIXME: Mandatory in SUSv4, optional in SUSv3.
# Not implemented in GCC/newlib, so far.
AC_CHECK_DECLS([WORD_BIT],,,[#include <limits.h>])
AC_CHECK_DECLS([LONG_BIT],,,[#include <limits.h>])
@@ -372,6 +372,19 @@ AM_CONDITIONAL([RPCTOOLS],[test "$RPCGEN" = rpcgen \
&& test -n "$AWK" \
&& test "$enable_rpcgen" = yes])
# Filter dynamic loading to only build for architectures that have
# reloc backends
AC_MSG_CHECKING([whether CPU supports libdl])
case $RTEMS_CPU in
arm | bfin | h8300 | i386 | lm32 | m32r | m68k | mips | \
moxie | nios2 | powerpc | sparc | v850)
HAVE_LIBDL=yes ;;
*)
HAVE_LIBDL=no ;;
esac
AM_CONDITIONAL(LIBDL,[test x"$HAVE_LIBDL" = x"yes"])
AC_MSG_RESULT([$HAVE_LIBDL])
RTEMS_AMPOLISH3
# Explicitly list all Makefiles here
@@ -412,6 +425,7 @@ librpc/Makefile
libmisc/Makefile
libi2c/Makefile
libmd/Makefile
libdl/Makefile
zlib/Makefile
ftpd/Makefile
telnetd/Makefile

36
cpukit/libdl/Makefile.am Normal file
View File

@@ -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

117
cpukit/libdl/dlfcn-shell.c Normal file
View File

@@ -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;
}

View File

@@ -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

153
cpukit/libdl/dlfcn.c Normal file
View File

@@ -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;
}

112
cpukit/libdl/dlfcn.h Normal file
View File

@@ -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_) */

551
cpukit/libdl/fastlz.c Normal file
View File

@@ -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) */

100
cpukit/libdl/fastlz.h Normal file
View File

@@ -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 */

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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_ */

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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_ */

View File

@@ -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_ */

View File

@@ -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_ */

File diff suppressed because it is too large Load Diff

View File

@@ -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

106
cpukit/libdl/rap-shell.c Normal file
View File

@@ -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;
}

14
cpukit/libdl/rap-shell.h Normal file
View File

@@ -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

484
cpukit/libdl/rap.c Normal file
View File

@@ -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;
}

115
cpukit/libdl/rap.h Normal file
View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

882
cpukit/libdl/rtl-elf.c Normal file
View File

@@ -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 (&sects, &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;
}

165
cpukit/libdl/rtl-elf.h Normal file
View File

@@ -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

47
cpukit/libdl/rtl-error.c Normal file
View File

@@ -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;
}

44
cpukit/libdl/rtl-error.h Normal file
View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

33
cpukit/libdl/rtl-fwd.h Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

179
cpukit/libdl/rtl-obj-comp.c Normal file
View File

@@ -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;
}

122
cpukit/libdl/rtl-obj-comp.h Normal file
View File

@@ -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

View File

@@ -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

1031
cpukit/libdl/rtl-obj.c Normal file

File diff suppressed because it is too large Load Diff

580
cpukit/libdl/rtl-obj.h Normal file
View File

@@ -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

980
cpukit/libdl/rtl-rap.c Normal file
View File

@@ -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;
}

54
cpukit/libdl/rtl-rap.h Normal file
View File

@@ -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

389
cpukit/libdl/rtl-shell.c Normal file
View File

@@ -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;
}

39
cpukit/libdl/rtl-shell.h Normal file
View File

@@ -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

32
cpukit/libdl/rtl-string.c Normal file
View File

@@ -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;
}

37
cpukit/libdl/rtl-string.h Normal file
View File

@@ -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

245
cpukit/libdl/rtl-sym.c Normal file
View File

@@ -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;
}
}

128
cpukit/libdl/rtl-sym.h Normal file
View File

@@ -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

134
cpukit/libdl/rtl-trace.c Normal file
View File

@@ -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

100
cpukit/libdl/rtl-trace.h Normal file
View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

637
cpukit/libdl/rtl.c Normal file
View File

@@ -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;
}

320
cpukit/libdl/rtl.h Normal file
View File

@@ -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

View File

@@ -46,7 +46,6 @@ $(PROJECT_INCLUDE)/utf8proc/utf8proc.h: libmisc/utf8proc/utf8proc.h $(PROJECT_IN
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/utf8proc/utf8proc.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/utf8proc/utf8proc.h
if NEWLIB
$(PROJECT_INCLUDE)/sys/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/sys
@: > $(PROJECT_INCLUDE)/sys/$(dirstamp)
@@ -130,6 +129,92 @@ $(PROJECT_INCLUDE)/rtems/bsdnet/_types.h: libnetworking/rtems/bsdnet/_types.h $(
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bsdnet/_types.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bsdnet/_types.h
endif
if LIBDL
$(PROJECT_INCLUDE)/dlfcn.h: libdl/dlfcn.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/dlfcn.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/dlfcn.h
$(PROJECT_INCLUDE)/link.h: libdl/include/link.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/link.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/link.h
$(PROJECT_INCLUDE)/link_elf.h: libdl/include/link_elf.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/link_elf.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/link_elf.h
$(PROJECT_INCLUDE)/sys/cdefs_elf.h: libdl/include/sys/cdefs_elf.h $(PROJECT_INCLUDE)/sys/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/cdefs_elf.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/cdefs_elf.h
$(PROJECT_INCLUDE)/sys/exec_elf.h: libdl/include/sys/exec_elf.h $(PROJECT_INCLUDE)/sys/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/exec_elf.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/exec_elf.h
$(PROJECT_INCLUDE)/machine/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/machine
@: > $(PROJECT_INCLUDE)/machine/$(dirstamp)
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/machine/$(dirstamp)
$(PROJECT_INCLUDE)/machine/elf_machdep.h: libdl/include/arch/@RTEMS_CPU@/machine/elf_machdep.h $(PROJECT_INCLUDE)/machine/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/machine/elf_machdep.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/machine/elf_machdep.h
$(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/rtems/rtl
@: > $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(PROJECT_INCLUDE)/rtems/rtl/dlfcn-shell.h: libdl/dlfcn-shell.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/dlfcn-shell.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/dlfcn-shell.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl.h: libdl/rtl.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl-allocator.h: libdl/rtl-allocator.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-allocator.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-allocator.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl-obj-fwd.h: libdl/rtl-obj-fwd.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-obj-fwd.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-obj-fwd.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl-fwd.h: libdl/rtl-fwd.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-fwd.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-fwd.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl-obj.h: libdl/rtl-obj.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-obj.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-obj.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl-obj-cache.h: libdl/rtl-obj-cache.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-obj-cache.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-obj-cache.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl-obj-comp.h: libdl/rtl-obj-comp.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-obj-comp.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-obj-comp.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl-unresolved.h: libdl/rtl-unresolved.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-unresolved.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-unresolved.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl-indirect-ptr.h: libdl/rtl-indirect-ptr.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-indirect-ptr.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-indirect-ptr.h
$(PROJECT_INCLUDE)/rtems/rtl/rtl-sym.h: libdl/rtl-sym.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-sym.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-sym.h
$(PROJECT_INCLUDE)/rtems/rtl/rap.h: libdl/rap.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rap.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rap.h
$(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h: libdl/rap-shell.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h
endif
$(PROJECT_INCLUDE)/rtems/bspIo.h: include/rtems/bspIo.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bspIo.h

View File

@@ -77,6 +77,10 @@ if NEWLIB
TMP_LIBS += ../libmd/libmd.a
endif
if LIBDL
TMP_LIBS += ../libdl/libdl.a
endif
librtemscpu.a: $(TMP_LIBS)
rm -f $@
$(MKDIR_P) $(ARCH)

View File

@@ -14,7 +14,7 @@ _SUBDIRS += block14
_SUBDIRS += block13
_SUBDIRS += rbheap01
_SUBDIRS += flashdisk01
_SUBDIRS += capture01
_SUBDIRS += capture01
_SUBDIRS += bspcmdline01 cpuuse devfs01 devfs02 devfs03 devfs04 \
deviceio01 devnullfatal01 dumpbuf01 gxx01 top\
@@ -36,5 +36,9 @@ _SUBDIRS += ftp01
_SUBDIRS += syscall01
endif
if DLTESTS
_SUBDIRS += dl01
endif
include $(top_srcdir)/../automake/test-subdirs.am
include $(top_srcdir)/../automake/local.am

View File

@@ -41,6 +41,29 @@ AM_CONDITIONAL([HAS_COMPLEX],[test "$ac_cv_header_complex_h" = yes])
AM_CONDITIONAL(NETTESTS,test "$rtems_cv_RTEMS_NETWORKING" = "yes")
AM_CONDITIONAL(HAS_POSIX,test x"${rtems_cv_RTEMS_POSIX_API}" = x"yes")
# Must match the list in cpukit.
AC_MSG_CHECKING([whether CPU supports libdl])
case $RTEMS_CPU in
arm | bfin | h8300 | i386 | lm32 | m32r | m68k | mips | \
moxie | nios2 | powerpc | sparc | v850)
HAVE_LIBDL=yes ;;
*)
HAVE_LIBDL=no ;;
esac
AM_CONDITIONAL(DLTESTS,[test x"$HAVE_LIBDL" = x"yes"])
AC_MSG_RESULT([$HAVE_LIBDL])
AS_IF([test x"$HAVE_LIBDL" = x"yes"],[
AC_CHECK_PROG(RTEMS_LD_CHECK,rtems-ld,yes)
if test x"$RTEMS_LD_CHECK" != x"yes" ; then
AC_MSG_ERROR([Please install rtems-tools.])
fi
AC_CHECK_PROG(RTEMS_SYMS_CHECK,rtems-syms,yes)
if test x"$RTEMS_SYMS_CHECK" != x"yes" ; then
AC_MSG_ERROR([Please install rtems-tools.])
fi
])
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
newlib01/Makefile
@@ -78,6 +101,7 @@ devfs03/Makefile
devfs04/Makefile
deviceio01/Makefile
devnullfatal01/Makefile
dl01/Makefile
dumpbuf01/Makefile
ftp01/Makefile
gxx01/Makefile

View File

@@ -0,0 +1,43 @@
rtems_tests_PROGRAMS = dl01
dl01_SOURCES = init.c dl-load.c dl-tar.c dl-tar.h
BUILT_SOURCES = dl-tar.c dl-tar.h
dist_rtems_tests_DATA = dl01.scn dl01.doc
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../automake/compile.am
include $(top_srcdir)/../automake/leaf.am
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
LINK_OBJS = $(dl01_OBJECTS)
LINK_LIBS = $(dl01_LDLIBS)
dl-o1.o: dl-o1.c
dl.tar: dl-o1.o
@rm -f $@
$(PAX) -w -f $@ $<
dl-tar.c: dl.tar
$(BIN2C) -C $< $@
CLEANFILES += dl-tar.c
dl-tar.h: dl.tar
$(BIN2C) -H $< $@
CLEANFILES += dl-tar.h
dl01.pre$(EXEEXT): $(dl01_OBJECTS) $(dl01_DEPENDENCIES)
@rm -f dl01.pre$(EXEEXT)
$(make-exe)
dl-sym.o: dl01.pre$(EXEEXT)
rtems-syms -e -c "$(CFLAGS)" -o $@ $<
dl01$(EXEEXT): $(dl01_OBJECTS) $(dl01_DEPENDENCIES) dl-sym.o
@rm -f dl01$(EXEEXT)
$(LINK.c) $(CPU_CFLAGS) $(AM_CFLAGS) $(AM_LDFLAGS) \
-o $(basename $@)$(EXEEXT) $(LINK_OBJS) dl-sym.o $(LINK_LIBS)
include $(top_srcdir)/../automake/local.am

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2014 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* 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.
*/
#include <stdio.h>
#include <dlfcn.h>
#include "dl-load.h"
typedef int (*call_t)(int argc, char* argv[]);
static const char* call_1[] = { "Line 1", "Line 2" };
static const char* call_2[] = { "Call 2, line 1",
"Call 2, line 2",
"Call 2, line 3" };
int dl_load_test(void)
{
void* handle;
call_t call;
int call_ret;
int unresolved;
char* message = "loaded";
printf("load: /dl-o1.o\n");
handle = dlopen ("/dl-o1.o", RTLD_NOW | RTLD_GLOBAL);
if (!handle)
{
printf("dlopen failed: %s\n", dlerror());
return 1;
}
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);
call = dlsym (handle, "rtems_main");
if (call == NULL)
{
printf("dlsym failed: symbol not found\n");
return 1;
}
call_ret = call (2, call_1);
if (call_ret != 2)
{
printf("dlsym call failed: ret value bad\n");
return 1;
}
call_ret = call (3, call_2);
if (call_ret != 3)
{
printf("dlsym call failed: ret value bad\n");
return 1;
}
if (dlclose (handle) < 0)
{
printf("dlclose failed: %s\n", dlerror());
return 1;
}
printf ("handle: %p closed\n", handle);
return 0;
}

View File

@@ -0,0 +1,14 @@
/*
* Copyright (c) 2014 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* 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.
*/
#if !defined(_DL_LOAD_H_)
#define _DL_LOAD_H_
int dl_load_test(void);
#endif

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2014 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
/**
* Hello World as a loadable module.
*/
#include <stdio.h>
/*
* Yes a decl in the source. This is a modules main and I could not find which
* header main is defined in.
*/
int rtems_main (int argc, char* argv[]);
int rtems_main (int argc, char* argv[])
{
int arg;
printf("Loaded module: argc:%d [%s]\n", argc, __FILE__);
for (arg = 0; arg < argc; ++arg)
printf(" %d: %s\n", arg, argv[arg]);
return argc;
}

View File

View File

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2014 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tmacros.h"
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <rtems/rtl/rtl.h>
#include <rtems/untar.h>
#include "dl-load.h"
const char rtems_test_name[] = "libdl (RTL) Loader 1";
/* forward declarations to avoid warnings */
static rtems_task Init(rtems_task_argument argument);
#include "dl-tar.h"
#define TARFILE_START dl_tar
#define TARFILE_SIZE dl_tar_size
static int test(void)
{
int ret;
ret = dl_load_test();
if (ret)
rtems_test_exit(ret);
return 0;
}
static void Init(rtems_task_argument arg)
{
int te;
TEST_BEGIN();
te = Untar_FromMemory((void *)TARFILE_START, (size_t)TARFILE_SIZE);
if (te != 0)
{
printf("untar failed: %d\n", te);
rtems_test_exit(1);
exit (1);
}
test();
TEST_END();
rtems_test_exit(0);
}
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 4
#define CONFIGURE_MAXIMUM_TASKS 1
#define CONFIGURE_MINIMUM_TASK_STACK_SIZE (8U * 1024U)
#define CONFIGURE_EXTRA_TASK_STACKS (8 * 1024)
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT
#include <rtems/confdefs.h>