summaryrefslogtreecommitdiff
path: root/rtl-rap.c
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2012-11-29 19:08:57 +1100
committerChris Johns <chrisj@rtems.org>2012-11-29 19:08:57 +1100
commitfc313fda72db4b7aa774e191244bf83427b0fec1 (patch)
tree159e98d0ffaa489a4f4b3deb7ca49178df8bfa2a /rtl-rap.c
parent62b19fe866226b8fa0ce54351162dab367daa06a (diff)
RAP file support.
This is the initial addition of support for LZ77 RTEMS applications in the RAP format. The change add support for different formats to the loader. Each format type is asked to check the file being loading and if it matches the format's loader is called to load the file. Support has been added to stream LZ77 files via the object file cache.
Diffstat (limited to 'rtl-rap.c')
-rw-r--r--rtl-rap.c453
1 files changed, 453 insertions, 0 deletions
diff --git a/rtl-rap.c b/rtl-rap.c
new file mode 100644
index 0000000..b54e38a
--- /dev/null
+++ b/rtl-rap.c
@@ -0,0 +1,453 @@
+/*
+ * 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 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 <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 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 sections as loaded from a RAP file.
+ */
+static const rtems_rtl_rap_sectdef_t rap_sections[6] =
+{
+ { ".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 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 number of RAP sections to load.
+ */
+#define RAP_SECTIONS (sizeof (rap_sections) / sizeof (rtems_rtl_rap_section_t))
+
+/**
+ * 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. */
+ uint32_t offset; /**< The offset 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. */
+ rtems_rtl_rap_section_t secs[RTEMS_RTL_RAP_SECS]; /**< The sections. */
+} 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)
+{
+ return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+}
+
+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_symbols (rtems_rtl_obj_t* obj,
+ int fd,
+ rtems_rtl_obj_sect_t* sect,
+ void* data)
+{
+ return true;
+}
+
+static bool
+rtems_rtl_rap_relocator (rtems_rtl_obj_t* obj,
+ int fd,
+ rtems_rtl_obj_sect_t* sect,
+ void* data)
+{
+ 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);
+
+ /*
+ * uint32_t: machinetype
+ * uint32_t: datatype
+ * uint32_t: class
+ */
+
+ 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: text_size
+ * uint32_t: text_alignment
+ * uint32_t: text_offset
+ * uint32_t: const_size
+ * uint32_t: const_alignment
+ * uint32_t: const_offset
+ * uint32_t: ctor_size
+ * uint32_t: ctor_alignment
+ * uint32_t: ctor_offset
+ * uint32_t: dtor_size
+ * uint32_t: dtor_alignment
+ * uint32_t: dtor_offset
+ * uint32_t: data_size
+ * uint32_t: data_alignment
+ * uint32_t: data_offset
+ * uint32_t: bss_size
+ * uint32_t: bss_alignment
+ * uint32_t: bss_offset
+ */
+
+ for (section = 0; section < RAP_SECTIONS; ++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_rap_read_uint32 (rap.decomp, &rap.secs[section].offset))
+ return false;
+
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD))
+ printf ("rtl: rap: %s: size=%lu align=%lu off=%lu\n",
+ rap_sections[section].name,
+ rap.secs[section].size,
+ rap.secs[section].alignment,
+ rap.secs[section].offset);
+
+ if (!rtems_rtl_obj_add_section (obj,
+ section,
+ rap_sections[section].name,
+ rap.secs[section].size,
+ rap.secs[section].offset,
+ 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))
+ return false;
+
+ if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_rap_symbols, &rap))
+ return false;
+
+ if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_rap_relocator, &rap))
+ return false;
+
+ return true;
+}