diff options
author | Chris Johns <chrisj@rtems.org> | 2014-10-26 18:09:41 -0700 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2014-10-31 11:04:15 +1100 |
commit | ae5fe7e6bca2874c5f1ef077204bb63124fb3db3 (patch) | |
tree | 90a6e9e7b414ed3713011267b1fee404b5f6093f /cpukit/libdl/rtl-rap.c | |
parent | Added missing stm32f4xxxx_adc.h (diff) | |
download | rtems-ae5fe7e6bca2874c5f1ef077204bb63124fb3db3.tar.bz2 |
cpukit: Add libdl with the Runtime Loader (RTL) code.
This is a merge of the RTL project.
Diffstat (limited to 'cpukit/libdl/rtl-rap.c')
-rw-r--r-- | cpukit/libdl/rtl-rap.c | 980 |
1 files changed, 980 insertions, 0 deletions
diff --git a/cpukit/libdl/rtl-rap.c b/cpukit/libdl/rtl-rap.c new file mode 100644 index 0000000000..ad05b245eb --- /dev/null +++ b/cpukit/libdl/rtl-rap.c @@ -0,0 +1,980 @@ +/* + * COPYRIGHT (c) 2012-2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor + * + * This is the RAP format loader support.. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include "rtl-obj-comp.h" +#include "rtl-rap.h" +#include "rtl-trace.h" +#include "rtl-unresolved.h" + +/** + * The offsets in the unresolved array. + */ +#define REL_R_OFFSET (0) +#define REL_R_INFO (1) +#define REL_R_ADDEND (2) + +/** + * The ELF format signature. + */ +static rtems_rtl_loader_format_t rap_sig = +{ + .label = "RAP", + .flags = RTEMS_RTL_FMT_COMP +}; + +/** + * The section definitions found in a RAP file. + */ +typedef struct rtems_rtl_rap_sectdef_s +{ + const char* name; /**< Name of the section. */ + const uint32_t flags; /**< Section flags. */ +} rtems_rtl_rap_sectdef_t; + +/** + * The section indexes. These are fixed. + */ +#define RTEMS_RTL_RAP_TEXT_SEC (0) +#define RTEMS_RTL_RAP_CONST_SEC (1) +#define RTEMS_RTL_RAP_CTOR_SEC (2) +#define RTEMS_RTL_RAP_DTOR_SEC (3) +#define RTEMS_RTL_RAP_DATA_SEC (4) +#define RTEMS_RTL_RAP_BSS_SEC (5) +#define RTEMS_RTL_RAP_SECS (6) + +/** + * The sections as loaded from a RAP file. + */ +static const rtems_rtl_rap_sectdef_t rap_sections[RTEMS_RTL_RAP_SECS] = +{ + { ".text", RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD }, + { ".const", RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD }, + { ".ctor", RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_CTOR }, + { ".dtor", RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_DTOR }, + { ".data", RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD }, + { ".bss", RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO } +}; + +/** + * The section definitions found in a RAP file. + */ +typedef struct rtems_rtl_rap_section_s +{ + uint32_t size; /**< The size of the section. */ + uint32_t alignment; /**< The alignment of the section. */ +} rtems_rtl_rap_section_t; + +/** + * The RAP loader. + */ +typedef struct rtems_rtl_rap_s +{ + rtems_rtl_obj_cache_t* file; /**< The file cache for the RAP file. */ + rtems_rtl_obj_comp_t* decomp; /**< The decompression streamer. */ + uint32_t length; /**< The file length. */ + uint32_t version; /**< The RAP file version. */ + uint32_t compression; /**< The type of compression. */ + uint32_t checksum; /**< The checksum. */ + uint32_t machinetype; /**< The ELF machine type. */ + uint32_t datatype; /**< The ELF data type. */ + uint32_t class; /**< The ELF class. */ + uint32_t init; /**< The initialisation strtab offset. */ + uint32_t fini; /**< The finish strtab offset. */ + rtems_rtl_rap_section_t secs[RTEMS_RTL_RAP_SECS]; /**< The sections. */ + uint32_t symtab_size; /**< The symbol table size. */ + char* strtab; /**< The string table. */ + uint32_t strtab_size; /**< The string table size. */ + uint32_t relocs_size; /**< The relocation table size. */ + uint32_t symbols; /**< The number of symbols. */ + uint32_t strtable_size;/**< The size of section names and obj names. */ + uint32_t rpathlen; /**< The length of rpath. */ + char* strtable; /**< The detail string which resides in obj detail. */ +} rtems_rtl_rap_t; + +/** + * Check the machine type. + */ +static bool +rtems_rtl_rap_machine_check (uint32_t machinetype) +{ + /* + * This code is determined by the machine headers. + */ + switch (machinetype) + { + ELFDEFNNAME (MACHDEP_ID_CASES) + default: + return false; + } + return true; +} + +/** + * Check the data type. + */ +static bool +rtems_rtl_rap_datatype_check (uint32_t datatype) +{ + /* + * This code is determined by the machine headers. + */ + if (datatype != ELFDEFNNAME (MACHDEP_ENDIANNESS)) + return false; + return true; +} + +/** + * Check the class of executable. + */ +static bool +rtems_rtl_rap_class_check (uint32_t class) +{ + /* + * This code is determined by the machine headers. + */ + switch (class) + { + case ELFCLASS32: + if (ARCH_ELFSIZE == 32) + return true; + break; + case ELFCLASS64: + if (ARCH_ELFSIZE == 64) + return true; + break; + default: + break; + } + return false; +} + +static uint32_t +rtems_rtl_rap_get_uint32 (const uint8_t* buffer) +{ + uint32_t value = 0; + int b; + for (b = 0; b < sizeof (uint32_t); ++b) + { + value <<= 8; + value |= buffer[b]; + } + return value; +} + +static bool +rtems_rtl_rap_read_uint32 (rtems_rtl_obj_comp_t* comp, uint32_t* value) +{ + uint8_t buffer[sizeof (uint32_t)]; + + if (!rtems_rtl_obj_comp_read (comp, buffer, sizeof (uint32_t))) + return false; + + *value = rtems_rtl_rap_get_uint32 (buffer); + + return true; +} + +static bool +rtems_rtl_rap_loader (rtems_rtl_obj_t* obj, + int fd, + rtems_rtl_obj_sect_t* sect, + void* data) +{ + rtems_rtl_rap_t* rap = (rtems_rtl_rap_t*) data; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input %s=%lu\n", + sect->name, rtems_rtl_obj_comp_input (rap->decomp)); + + return rtems_rtl_obj_comp_read (rap->decomp, sect->base, sect->size); +} + +static bool +rtems_rtl_rap_relocate (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) +{ + #define SYMNAME_BUFFER_SIZE (1024) + char* symname_buffer = NULL; + int section; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: relocation\n"); + + symname_buffer = malloc (SYMNAME_BUFFER_SIZE); + if (!symname_buffer) + { + rtems_rtl_set_error (ENOMEM, "no memory for local symbol name buffer"); + return false; + } + + for (section = 0; section < RTEMS_RTL_RAP_SECS; ++section) + { + rtems_rtl_obj_sect_t* targetsect; + uint32_t header = 0; + int relocs; + bool is_rela; + int r; + + targetsect = rtems_rtl_obj_find_section (obj, rap_sections[section].name); + + if (!targetsect) + { + rtems_rtl_set_error (EINVAL, "no target section found"); + free (symname_buffer); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &header)) + { + free (symname_buffer); + return false; + } + + /* + * Bit 31 of the header indicates if the relocations for this section + * have a valid addend field. + */ + + is_rela = (header & (1 << 31)) != 0 ? true : false; + relocs = header & ~(1 << 31); + + if (relocs && rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: relocation: %s: header: %08lx relocs: %d %s\n", + rap_sections[section].name, + header, relocs, is_rela ? "rela" : "rel"); + + for (r = 0; r < relocs; ++r) + { + uint32_t info = 0; + uint32_t offset = 0; + uint32_t addend = 0; + Elf_Word type; + const char* symname = NULL; + uint32_t symname_size; + Elf_Word symtype = 0; + Elf_Word symvalue = 0; + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &info)) + { + free (symname_buffer); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &offset)) + { + free (symname_buffer); + return false; + } + + /* + * The types are: + * + * 0 Section symbol offset in addend. + * 1 Symbol appended to the relocation record. + * 2 Symbol is in the strtabl. + * + * If type 2 bits 30:8 is the offset in the strtab. If type 1 the bits + * are the size of the string. The lower 8 bits of the info field if the + * ELF relocation type field. + */ + + if (((info & (1 << 31)) == 0) || is_rela) + { + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &addend)) + { + free (symname_buffer); + return false; + } + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf (" %2d: info=%08lx offset=%lu addend=%lu\n", + r, info, offset, addend); + + type = info & 0xff; + + if ((info & (1 << 31)) == 0) + { + rtems_rtl_obj_sect_t* symsect; + + symsect = rtems_rtl_obj_find_section_by_index (obj, info >> 8); + if (!symsect) + { + free (symname_buffer); + return false; + } + + symvalue = (Elf_Word) symsect->base + addend; + } + else if (rtems_rtl_elf_rel_resolve_sym (type)) + { + rtems_rtl_obj_sym_t* symbol; + + symname_size = (info & ~(3 << 30)) >> 8; + + if ((info & (1 << 30)) != 0) + { + symname = rap->strtab + symname_size; + } + else + { + if (symname_size > (SYMNAME_BUFFER_SIZE - 1)) + { + free (symname_buffer); + rtems_rtl_set_error (EINVAL, "reloc symbol too big"); + return false; + } + + if (!rtems_rtl_obj_comp_read (rap->decomp, symname_buffer, symname_size)) + { + free (symname_buffer); + return false; + } + + symname_buffer[symname_size] = '\0'; + symname = symname_buffer; + } + + symbol = rtems_rtl_symbol_obj_find (obj, symname); + + if (!symbol) + { + rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname); + free (symname_buffer); + return false; + } + + symvalue = (Elf_Word) symbol->value; + } + + if (is_rela) + { + Elf_Rela rela; + + rela.r_offset = offset; + rela.r_info = type; + + if ((info & (1 << 31)) == 0) + rela.r_addend = 0; + else rela.r_addend = addend; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf (" %2d: rela: type:%-2d off:%lu addend:%d" \ + " symname=%s symtype=%lu symvalue=0x%08lx\n", + r, (int) type, offset, (int) addend, + symname, symtype, symvalue); + + if (!rtems_rtl_elf_relocate_rela (obj, &rela, targetsect, + symname, symtype, symvalue)) + { + free (symname_buffer); + return false; + } + } + else + { + Elf_Rel rel; + + rel.r_offset = offset; + rel.r_info = type; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf (" %2d: rel: type:%-2d off:%lu" \ + " symname=%s symtype=%lu symvalue=0x%08lx\n", + r, (int) type, offset, + symname, symtype, symvalue); + + if (!rtems_rtl_elf_relocate_rel (obj, &rel, targetsect, + symname, symtype, symvalue)) + { + free (symname_buffer); + return false; + } + } + } + } + + free (symname_buffer); + + return true; +} + +/** + * The structure of obj->detail is + * + * |object_detail(0..obj_num)|section_detail(0..sec_num[0..obj_num])| + * obj_name(0..obj_num)|section_name(0..sec_num[0..obj_num]) + * + */ +static bool +rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) +{ + struct link_map* tmp1; + section_detail* tmp2; + uint32_t obj_detail_size; + uint32_t pos = 0; + int i,j; + + obj_detail_size = sizeof (struct link_map) * obj->obj_num; + + for (i = 0; i < obj->obj_num; ++i) + { + obj_detail_size += (obj->sec_num[i] * sizeof (section_detail)); + } + + obj->detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, + obj_detail_size + rap->strtable_size, true); + + if (!obj->detail) + { + rap->strtable_size = 0; + rtems_rtl_set_error (ENOMEM, "no memory for obj global syms"); + return false; + } + + rap->strtable = obj->detail + obj_detail_size; + + /* Read the obj names and section names */ + if (!rtems_rtl_obj_comp_read (rap->decomp, rap->strtable, + rap->strtable_size)) + { + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj->detail); + return false; + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + { + if (rap->rpathlen > 0) + printf ("File rpath:\n"); + } + + while (pos < rap->rpathlen) + { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + { + printf (" %s\n", rap->strtable + pos); + } + pos = pos + strlen (rap->strtable + pos) + 1; + } + + if (rap->rpathlen > 0) + pos = rap->rpathlen; + + for (i = 0; i < obj->obj_num; ++i) + { + tmp1 = (struct link_map*) (obj->detail) + i; + tmp1->name = rap->strtable + pos; + tmp1->sec_num = obj->sec_num[i]; + tmp1->rpathlen = rap->rpathlen; + tmp1->rpath = (char*) rap->strtable; + pos += strlen (tmp1->name) + 1; + + if (!i) + { + tmp1->l_next = NULL; + tmp1->l_prev = NULL; + } + else + { + (tmp1 - 1)->l_next = tmp1; + tmp1->l_prev = tmp1 - 1; + tmp1->l_next = NULL; + } + } + + tmp2 =(section_detail*) ((struct link_map*) (obj->detail) + obj->obj_num); + + for (i = 0; i < obj->obj_num; ++i) + { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + { + printf ("File %d: %s\n", i, ((struct link_map*) obj->detail + i)->name); + printf ("Section: %d sections\n",(unsigned int) obj->sec_num[i]); + } + + ((struct link_map*)obj->detail + i)->sec_detail = tmp2; + + for (j = 0; j < obj->sec_num[i]; ++j) + { + uint32_t name; + uint32_t rap_id; + uint32_t offset; + uint32_t size; + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &name) || + !rtems_rtl_rap_read_uint32 (rap->decomp, &offset) || + !rtems_rtl_rap_read_uint32 (rap->decomp, &size)) + { + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->detail); + return false; + } + + rap_id = offset >> 28; + offset = offset & 0xfffffff; + + tmp2->name = rap->strtable + name; + tmp2->offset = offset; + tmp2->rap_id = rap_id; + tmp2->size = size; + pos += strlen (tmp2->name) + 1; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + { + printf ("name:%16s offset:0x%08x rap_id:%d size:0x%x\n", + tmp2->name, (unsigned int) tmp2->offset, + (unsigned int) tmp2->rap_id, (unsigned int) tmp2->size); + } + + tmp2 += 1; + } + } + return true; +} + +static bool +rtems_rtl_rap_load_symbols (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj) +{ + rtems_rtl_obj_sym_t* gsym; + int sym; + + obj->global_size = + rap->symbols * sizeof (rtems_rtl_obj_sym_t) + rap->strtab_size; + + obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, + obj->global_size, true); + if (!obj->global_table) + { + obj->global_size = 0; + rtems_rtl_set_error (ENOMEM, "no memory for obj global syms"); + return false; + } + + obj->global_syms = rap->symbols; + + rap->strtab = (((char*) obj->global_table) + + (rap->symbols * sizeof (rtems_rtl_obj_sym_t))); + + if (!rtems_rtl_obj_comp_read (rap->decomp, rap->strtab, rap->strtab_size)) + return false; + + for (sym = 0, gsym = obj->global_table; sym < rap->symbols; ++sym) + { + rtems_rtl_obj_sect_t* symsect; + uint32_t data; + uint32_t name; + uint32_t value; + + if (!rtems_rtl_rap_read_uint32 (rap->decomp, &data) || + !rtems_rtl_rap_read_uint32 (rap->decomp, &name) || + !rtems_rtl_rap_read_uint32 (rap->decomp, &value)) + { + free (obj->global_table); + obj->global_table = NULL; + obj->global_syms = 0; + obj->global_size = 0; + return false; + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) + printf ("rtl: sym:load: data=0x%08lx name=0x%08lx value=0x%08lx\n", + data, name, value); + + /* + * If there is a globally exported symbol already present and this + * symbol is not weak raise an error. If the symbol is weak and present + * globally ignore this symbol and use the global one and if it is not + * present take this symbol global or weak. We accept the first weak + * symbol we find and make it globally exported. + */ + if (rtems_rtl_symbol_global_find (rap->strtab + name) && + (ELF_ST_BIND (data & 0xffff) != STB_WEAK)) + { + rtems_rtl_set_error (EINVAL, + "duplicate global symbol: %s", rap->strtab + name); + free (obj->global_table); + obj->global_table = NULL; + obj->global_syms = 0; + obj->global_size = 0; + return false; + } + + symsect = rtems_rtl_obj_find_section_by_index (obj, data >> 16); + if (!symsect) + { + free (obj->global_table); + obj->global_table = NULL; + obj->global_syms = 0; + obj->global_size = 0; + rtems_rtl_set_error (EINVAL, "section index not found: %lu", data >> 16); + return false; + } + + rtems_chain_set_off_chain (&gsym->node); + gsym->name = rap->strtab + name; + gsym->value = (uint8_t*) (value + symsect->base); + gsym->data = data & 0xffff; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) + printf ("rtl: sym:add:%-2d name:%-20s bind:%-2d type:%-2d val:%8p sect:%d\n", + sym, gsym->name, + (int) ELF_ST_BIND (data & 0xffff), + (int) ELF_ST_TYPE (data & 0xffff), + gsym->value, (int) (data >> 16)); + + ++gsym; + } + + return true; +} + +static bool +rtems_rtl_rap_parse_header (uint8_t* rhdr, + size_t* rhdr_len, + uint32_t* length, + uint32_t* version, + uint32_t* compression, + uint32_t* checksum) +{ + char* sptr = (char*) rhdr; + char* eptr; + + *rhdr_len = 0; + + /* + * "RAP," = 4 bytes, total 4 + */ + + if ((rhdr[0] != 'R') || (rhdr[1] != 'A') || (rhdr[2] != 'P') || (rhdr[3] != ',')) + return false; + + sptr = sptr + 4; + + /* + * "00000000," = 9 bytes, total 13 + */ + + *length = strtoul (sptr, &eptr, 10); + + if (*eptr != ',') + return false; + + sptr = eptr + 1; + + /* + * "0000," = 5 bytes, total 18 + */ + + *version = strtoul (sptr, &eptr, 10); + + if (*eptr != ',') + return false; + + sptr = eptr + 1; + + /* + * "NONE," and "LZ77," = 5 bytes, total 23 + */ + + if ((sptr[0] == 'N') && + (sptr[1] == 'O') && + (sptr[2] == 'N') && + (sptr[3] == 'E')) + { + *compression = RTEMS_RTL_COMP_NONE; + eptr = sptr + 4; + } + else if ((sptr[0] == 'L') && + (sptr[1] == 'Z') && + (sptr[2] == '7') && + (sptr[3] == '7')) + { + *compression = RTEMS_RTL_COMP_LZ77; + eptr = sptr + 4; + } + else + return false; + + if (*eptr != ',') + return false; + + sptr = eptr + 1; + + /* + * "00000000," = 9 bytes, total 32 + */ + *checksum = strtoul (sptr, &eptr, 16); + + /* + * "\n" = 1 byte, total 33 + */ + if (*eptr != '\n') + return false; + + *rhdr_len = ((uint8_t*) eptr) - rhdr + 1; + + return true; +} + +bool +rtems_rtl_rap_file_check (rtems_rtl_obj_t* obj, int fd) +{ + rtems_rtl_obj_cache_t* header; + uint8_t* rhdr = NULL; + size_t rlen = 64; + uint32_t length = 0; + uint32_t version = 0; + uint32_t compression = 0; + uint32_t checksum = 0; + + rtems_rtl_obj_caches (&header, NULL, NULL); + + if (!rtems_rtl_obj_cache_read (header, fd, obj->ooffset, + (void**) &rhdr, &rlen)) + return false; + + if (!rtems_rtl_rap_parse_header (rhdr, + &rlen, + &length, + &version, + &compression, + &checksum)) + return false; + + return true; +} + +bool +rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd) +{ + rtems_rtl_rap_t rap = { 0 }; + uint8_t* rhdr = NULL; + size_t rlen = 64; + int section; + + rtems_rtl_obj_caches (&rap.file, NULL, NULL); + + if (!rtems_rtl_obj_cache_read (rap.file, fd, obj->ooffset, + (void**) &rhdr, &rlen)) + return false; + + if (!rtems_rtl_rap_parse_header (rhdr, + &rlen, + &rap.length, + &rap.version, + &rap.compression, + &rap.checksum)) + { + rtems_rtl_set_error (EINVAL, "invalid RAP file format"); + return false; + } + + /* + * Set up the decompressor. + */ + rtems_rtl_obj_comp (&rap.decomp, rap.file, fd, rap.compression, + rlen + obj->ooffset); + + /* + * uint32_t: machinetype + * uint32_t: datatype + * uint32_t: class + */ + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input machine=%lu\n", + rtems_rtl_obj_comp_input (rap.decomp)); + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.machinetype)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: machinetype=%lu\n", rap.machinetype); + + if (!rtems_rtl_rap_machine_check (rap.machinetype)) + { + rtems_rtl_set_error (EINVAL, "invalid machinetype"); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.datatype)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: datatype=%lu\n", rap.datatype); + + if (!rtems_rtl_rap_datatype_check (rap.datatype)) + { + rtems_rtl_set_error (EINVAL, "invalid datatype"); + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.class)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: class=%lu\n", rap.class); + + if (!rtems_rtl_rap_class_check (rap.class)) + { + rtems_rtl_set_error (EINVAL, "invalid class"); + return false; + } + + /* + * uint32_t: init + * uint32_t: fini + * uint32_t: symtab_size + * uint32_t: strtab_size + * uint32_t: relocs_size + */ + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input header=%lu\n", + rtems_rtl_obj_comp_input (rap.decomp)); + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.init)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.fini)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.symtab_size)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.strtab_size)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.relocs_size)) + return false; + + rap.symbols = rap.symtab_size / (3 * sizeof (uint32_t)); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: load: symtab=%lu (%lu) strtab=%lu relocs=%lu\n", + rap.symtab_size, rap.symbols, + rap.strtab_size, rap.relocs_size); + + /* + * Load the details + */ + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &obj->obj_num)) + return false; + + if (obj->obj_num > 0) + { + obj->sec_num = (uint32_t*) malloc (sizeof (uint32_t) * obj->obj_num); + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.rpathlen)) + return false; + + uint32_t i; + for (i = 0; i < obj->obj_num; ++i) + { + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &(obj->sec_num[i]))) + return false; + } + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.strtable_size)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) + printf ("rtl: rap: details: obj_num=%lu\n", obj->obj_num); + + if (!rtems_rtl_rap_load_details (&rap, obj)) + return false; + } + + /* + * uint32_t: text_size + * uint32_t: text_alignment + * uint32_t: const_size + * uint32_t: const_alignment + * uint32_t: ctor_size + * uint32_t: ctor_alignment + * uint32_t: dtor_size + * uint32_t: dtor_alignment + * uint32_t: data_size + * uint32_t: data_alignment + * uint32_t: bss_size + * uint32_t: bss_alignment + */ + + for (section = 0; section < RTEMS_RTL_RAP_SECS; ++section) + { + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.secs[section].size)) + return false; + + if (!rtems_rtl_rap_read_uint32 (rap.decomp, &rap.secs[section].alignment)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT)) + printf ("rtl: rap: %s: size=%lu align=%lu\n", + rap_sections[section].name, + rap.secs[section].size, + rap.secs[section].alignment); + + if (!rtems_rtl_obj_add_section (obj, + section, + rap_sections[section].name, + rap.secs[section].size, + 0, + rap.secs[section].alignment, + 0, 0, + rap_sections[section].flags)) + return false; + } + + /** obj->entry = (void*)(uintptr_t) ehdr.e_entry; */ + + if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_rap_loader, &rap)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input symbols=%lu\n", + rtems_rtl_obj_comp_input (rap.decomp)); + + if (!rtems_rtl_rap_load_symbols (&rap, obj)) + return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) + printf ("rtl: rap: input relocs=%lu\n", + rtems_rtl_obj_comp_input (rap.decomp)); + + if (!rtems_rtl_rap_relocate (&rap, obj)) + return false; + + return true; +} + +rtems_rtl_loader_format_t* +rtems_rtl_rap_file_sig (void) +{ + return &rap_sig; +} |