summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2012-12-12 21:54:24 +1100
committerChris Johns <chrisj@rtems.org>2012-12-12 21:54:24 +1100
commita408634ee13315868a80484bd53c579096bec54e (patch)
treeeb81d31601fea5d2e53fea2bedf99850fa71139e
parentc4e952ed97c76f971c9f9b08f61978f0550d9732 (diff)
Relocation is almost working for RAP files.
-rw-r--r--rtl-elf.c14
-rw-r--r--rtl-rap.c244
2 files changed, 225 insertions, 33 deletions
diff --git a/rtl-elf.c b/rtl-elf.c
index 76bdf1b..d1d97dc 100644
--- a/rtl-elf.c
+++ b/rtl-elf.c
@@ -148,7 +148,7 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
const char* symname = NULL;
off_t off;
Elf_Word type;
- Elf_Word symvalue;
+ Elf_Word symvalue = 0;
bool relocate;
off = obj->ooffset + sect->offset + (reloc * reloc_size);
@@ -234,9 +234,9 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
if (is_rela)
{
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
- printf ("rtl: rela: sym:%s(%-2d) type:%-2d off:%08lx addend:%d\n",
- symname, (int) ELF_R_SYM (rela->r_info), (int) ELF_R_TYPE (rela->r_info),
- rela->r_offset, (int) rela->r_addend);
+ 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;
@@ -244,9 +244,9 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
else
{
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
- printf ("rtl: rel: sym:%s(%-2d) type:%-2d off:%08lx\n",
- symname, (int) ELF_R_SYM (rel->r_info), (int) ELF_R_TYPE (rel->r_info),
- rel->r_offset);
+ 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;
diff --git a/rtl-rap.c b/rtl-rap.c
index d8efcf8..bfedbb0 100644
--- a/rtl-rap.c
+++ b/rtl-rap.c
@@ -81,7 +81,6 @@ 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;
/**
@@ -102,6 +101,7 @@ typedef struct rtems_rtl_rap_s
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. */
@@ -167,7 +167,14 @@ rtems_rtl_rap_class_check (uint32_t class)
static uint32_t
rtems_rtl_rap_get_uint32 (const uint8_t* buffer)
{
- return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+ uint32_t value = 0;
+ int b;
+ for (b = 0; b < sizeof (uint32_t); ++b)
+ {
+ value <<= 8;
+ value |= buffer[b];
+ }
+ return value;
}
static bool
@@ -194,20 +201,208 @@ rtems_rtl_rap_loader (rtems_rtl_obj_t* obj,
}
static bool
-rtems_rtl_rap_symbols (rtems_rtl_obj_t* obj,
- int fd,
- rtems_rtl_obj_sect_t* sect,
- void* data)
+rtems_rtl_rap_relocate (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
{
- return true;
-}
+ #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;
+ }
+ 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)
+ {
+ free (symname_buffer);
+ rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname);
+ return false;
+ }
+
+ symvalue = (Elf_Word) symbol->value;
+ }
+
+ if (is_rela)
+ {
+ Elf_Rela rela;
+
+ rela.r_offset = offset;
+ rela.r_info = type;
+ 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);
-static bool
-rtems_rtl_rap_relocator (rtems_rtl_obj_t* obj,
- int fd,
- rtems_rtl_obj_sect_t* sect,
- void* data)
-{
return true;
}
@@ -232,8 +427,8 @@ rtems_rtl_rap_load_symbols (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
obj->global_syms = rap->symbols;
- string = (((char*) obj->global_table) +
- (rap->symbols * sizeof (rtems_rtl_obj_sym_t)));
+ rap->strtab = string = (((char*) obj->global_table) +
+ (rap->symbols * sizeof (rtems_rtl_obj_sym_t)));
if (!rtems_rtl_obj_comp_read (rap->decomp, string, rap->strtab_size))
return false;
@@ -270,7 +465,7 @@ rtems_rtl_rap_load_symbols (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
obj->global_table = NULL;
obj->global_syms = 0;
obj->global_size = 0;
- rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", string);
+ rtems_rtl_set_error (EINVAL, "duplicate global symbol: %s", string);
return false;
}
@@ -281,6 +476,7 @@ rtems_rtl_rap_load_symbols (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
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;
}
@@ -494,7 +690,7 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
/*
* uint32_t: init
* uint32_t: fini
- * uint32_t: symtabl_size
+ * uint32_t: symtab_size
* uint32_t: strtab_size
* uint32_t: relocs_size
*/
@@ -545,21 +741,17 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
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_SECT))
- printf ("rtl: rap: %s: size=%lu align=%lu off=%lu\n",
+ printf ("rtl: rap: %s: size=%lu align=%lu\n",
rap_sections[section].name,
rap.secs[section].size,
- rap.secs[section].alignment,
- rap.secs[section].offset);
+ rap.secs[section].alignment);
if (!rtems_rtl_obj_add_section (obj,
section,
rap_sections[section].name,
rap.secs[section].size,
- rap.secs[section].offset,
+ 0,
rap.secs[section].alignment,
0, 0,
rap_sections[section].flags))
@@ -574,7 +766,7 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
if (!rtems_rtl_rap_load_symbols (&rap, obj))
return false;
- if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_rap_relocator, &rap))
+ if (!rtems_rtl_rap_relocate (&rap, obj))
return false;
return true;