forked from Imagelibrary/rtems
libdl: Support link ordered loading of ELF sections.
The ARM C++ exception ABI uses an address ordered index table to locate the correct frame data and this requires the EXIDX sections are loaded in the order the order the matching text is loaded. The EXIDX sections set the SHF_LINK_ORDER flag and link field. This patch adds support to load those flagged sections in the linked-to section order. Updates #2955. Closes #2959
This commit is contained in:
@@ -459,6 +459,10 @@ typedef struct {
|
||||
#define SHF_WRITE 0x1 /* Section contains writable data */
|
||||
#define SHF_ALLOC 0x2 /* Section occupies memory */
|
||||
#define SHF_EXECINSTR 0x4 /* Section contains executable insns */
|
||||
#define SHF_MERGE 0x10 /* Section contains data that can be merged */
|
||||
#define SHF_STRINGS 0x20 /* Section contains null-terminated strings */
|
||||
#define SHF_INFO_LINK 0x40 /* Section header's sh_info holds table index */
|
||||
#define SHF_LINK_ORDER 0x80 /* Section has special ordering requirements */
|
||||
|
||||
#define SHF_MASKOS 0x0f000000 /* Operating system specific values */
|
||||
#define SHF_MASKPROC 0xf0000000 /* Processor-specific values */
|
||||
|
||||
@@ -656,6 +656,11 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
|
||||
|
||||
flags = 0;
|
||||
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||
printf ("rtl: section: %2d: type=%d flags=%08x link=%d info=%d\n",
|
||||
section, (int) shdr.sh_type, (unsigned int) shdr.sh_flags,
|
||||
(int) shdr.sh_link, (int) shdr.sh_info);
|
||||
|
||||
switch (shdr.sh_type)
|
||||
{
|
||||
case SHT_NULL:
|
||||
@@ -712,7 +717,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
|
||||
|
||||
default:
|
||||
/*
|
||||
* See there are architecture specific flags?
|
||||
* See if there are architecture specific flags?
|
||||
*/
|
||||
flags = rtems_rtl_elf_section_flags (obj, &shdr);
|
||||
if (flags == 0)
|
||||
@@ -729,6 +734,13 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
|
||||
char* name;
|
||||
size_t len;
|
||||
|
||||
/*
|
||||
* If link ordering this section must appear in the same order in memory
|
||||
* as the linked-to section relative to the sections it loads with.
|
||||
*/
|
||||
if ((shdr.sh_flags & SHF_LINK_ORDER) != 0)
|
||||
flags |= RTEMS_RTL_OBJ_SECT_LINK;
|
||||
|
||||
len = RTEMS_RTL_ELF_STRING_MAX;
|
||||
if (!rtems_rtl_obj_cache_read (strings, fd,
|
||||
sectstroff + shdr.sh_name,
|
||||
|
||||
@@ -253,7 +253,8 @@ rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj,
|
||||
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||
printf ("rtl: %s %p @ %p in %s\n",
|
||||
reloc_names[type], (void *)tmp, where, rtems_rtl_obj_oname (obj));
|
||||
reloc_names[ELF_R_TYPE(rela->r_info)],
|
||||
(void *)tmp, where, rtems_rtl_obj_oname (obj));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -601,12 +601,12 @@ typedef struct
|
||||
static bool
|
||||
rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
|
||||
{
|
||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||
rtems_rtl_obj_sect_sync_ctx_t* sync_ctx = data;
|
||||
uintptr_t old_end;
|
||||
uintptr_t new_start;
|
||||
uintptr_t old_end;
|
||||
uintptr_t new_start;
|
||||
|
||||
if ( !(sect->flags & sync_ctx->mask) || !sect->size)
|
||||
if ((sect->flags & sync_ctx->mask) == 0 || sect->size == 0)
|
||||
return true;
|
||||
|
||||
if (sync_ctx->end_va == sync_ctx->start_va)
|
||||
@@ -632,7 +632,7 @@ rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
|
||||
}
|
||||
|
||||
void
|
||||
rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t* obj)
|
||||
rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t* obj)
|
||||
{
|
||||
rtems_rtl_obj_sect_sync_ctx_t sync_ctx;
|
||||
|
||||
@@ -643,7 +643,7 @@ rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t* obj)
|
||||
|
||||
sync_ctx.mask = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST |
|
||||
RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_BSS |
|
||||
RTEMS_RTL_OBJ_SECT_EXEC;
|
||||
RTEMS_RTL_OBJ_SECT_EH | RTEMS_RTL_OBJ_SECT_EXEC;
|
||||
|
||||
sync_ctx.start_va = 0;
|
||||
sync_ctx.end_va = sync_ctx.start_va;
|
||||
@@ -667,6 +667,87 @@ rtems_rtl_obj_load_symbols (rtems_rtl_obj_t* obj,
|
||||
return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_rtl_obj_sections_linked_to_order (rtems_rtl_obj_t* obj,
|
||||
int section,
|
||||
uint32_t visited_mask)
|
||||
{
|
||||
rtems_chain_control* sections = &obj->sections;
|
||||
rtems_chain_node* node = rtems_chain_first (sections);
|
||||
/*
|
||||
* Find the section being linked-to. If the linked-to link field is 0 we have
|
||||
* the end and the section's order is the position we are after.
|
||||
*/
|
||||
while (!rtems_chain_is_tail (sections, node))
|
||||
{
|
||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||
if (sect->section == section)
|
||||
{
|
||||
const uint32_t mask = sect->flags & RTEMS_RTL_OBJ_SECT_TYPES;
|
||||
int order = 0;
|
||||
if (sect->link != 0)
|
||||
{
|
||||
/*
|
||||
* Have we already visited this type of section? Avoid nesting for
|
||||
* ever.
|
||||
*/
|
||||
if ((sect->flags & visited_mask) != 0)
|
||||
{
|
||||
rtems_rtl_set_error (errno, "section link loop");
|
||||
return -1;
|
||||
}
|
||||
return rtems_rtl_obj_sections_linked_to_order (obj,
|
||||
sect->link,
|
||||
visited_mask | mask);
|
||||
}
|
||||
node = rtems_chain_first (sections);
|
||||
while (!rtems_chain_is_tail (sections, node))
|
||||
{
|
||||
sect = (rtems_rtl_obj_sect_t*) node;
|
||||
if ((sect->flags & mask) == mask)
|
||||
{
|
||||
if (sect->section == section)
|
||||
return order;
|
||||
++order;
|
||||
}
|
||||
node = rtems_chain_next (node);
|
||||
}
|
||||
}
|
||||
node = rtems_chain_next (node);
|
||||
}
|
||||
rtems_rtl_set_error (errno, "section link not found");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
rtems_rtl_obj_sections_link_order (uint32_t mask, rtems_rtl_obj_t* obj)
|
||||
{
|
||||
rtems_chain_control* sections = &obj->sections;
|
||||
rtems_chain_node* node = rtems_chain_first (sections);
|
||||
int order = 0;
|
||||
while (!rtems_chain_is_tail (sections, node))
|
||||
{
|
||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||
if ((sect->flags & mask) == mask)
|
||||
{
|
||||
/*
|
||||
* If the section is linked in order find the linked-to section's order
|
||||
* and move the section in the section list to
|
||||
*/
|
||||
if (sect->link == 0)
|
||||
sect->load_order = order++;
|
||||
else
|
||||
{
|
||||
sect->load_order =
|
||||
rtems_rtl_obj_sections_linked_to_order (obj,
|
||||
sect->link,
|
||||
mask);
|
||||
}
|
||||
}
|
||||
node = rtems_chain_next (node);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
rtems_rtl_obj_sections_loader (uint32_t mask,
|
||||
rtems_rtl_obj_t* obj,
|
||||
@@ -679,42 +760,54 @@ rtems_rtl_obj_sections_loader (uint32_t mask,
|
||||
rtems_chain_node* node = rtems_chain_first (sections);
|
||||
size_t base_offset = 0;
|
||||
bool first = true;
|
||||
int order = 0;
|
||||
|
||||
while (!rtems_chain_is_tail (sections, node))
|
||||
{
|
||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||
|
||||
if ((sect->size != 0) && ((sect->flags & mask) != 0))
|
||||
{
|
||||
if (!first)
|
||||
base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
|
||||
|
||||
sect->base = base + base_offset;
|
||||
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
|
||||
printf ("rtl: loading: %s -> %8p (l:%zi m:%04lx)\n",
|
||||
sect->name, sect->base, sect->size, sect->flags);
|
||||
|
||||
if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
|
||||
if (sect->load_order == order)
|
||||
{
|
||||
if (!handler (obj, fd, sect, data))
|
||||
if (!first)
|
||||
base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
|
||||
|
||||
first = false;
|
||||
|
||||
sect->base = base + base_offset;
|
||||
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
|
||||
printf ("rtl: loading:%2d: %s -> %8p (s:%zi f:%04lx a:%lu l:%02d)\n",
|
||||
order, sect->name, sect->base, sect->size,
|
||||
sect->flags, sect->alignment, sect->link);
|
||||
|
||||
if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
|
||||
{
|
||||
if (!handler (obj, fd, sect, data))
|
||||
{
|
||||
sect->base = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
|
||||
{
|
||||
memset (base + base_offset, 0, sect->size);
|
||||
}
|
||||
else
|
||||
{
|
||||
sect->base = 0;
|
||||
rtems_rtl_set_error (errno, "section has no load/clear op");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
|
||||
{
|
||||
memset (base + base_offset, 0, sect->size);
|
||||
}
|
||||
else
|
||||
{
|
||||
sect->base = 0;
|
||||
rtems_rtl_set_error (errno, "section has no load op");
|
||||
return false;
|
||||
}
|
||||
|
||||
base_offset += sect->size;
|
||||
first = false;
|
||||
base_offset += sect->size;
|
||||
|
||||
++order;
|
||||
|
||||
node = rtems_chain_first (sections);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
node = rtems_chain_next (node);
|
||||
@@ -763,7 +856,7 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj,
|
||||
return false;
|
||||
}
|
||||
|
||||
obj->exec_size = text_size + const_size + data_size + bss_size;
|
||||
obj->exec_size = text_size + const_size + eh_size + data_size + bss_size;
|
||||
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
|
||||
{
|
||||
@@ -779,6 +872,14 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj,
|
||||
obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj));
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the load order.
|
||||
*/
|
||||
rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_TEXT, obj);
|
||||
rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_CONST, obj);
|
||||
rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_EH, obj);
|
||||
rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_DATA, obj);
|
||||
|
||||
/*
|
||||
* Load all text then data then bss sections in seperate operations so each
|
||||
* type of section is grouped together.
|
||||
|
||||
@@ -102,8 +102,19 @@ typedef struct rtems_rtl_loader_table_s
|
||||
#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 11) /**< Section is writable, ie data. */
|
||||
#define RTEMS_RTL_OBJ_SECT_EXEC (1 << 12) /**< Section is executable. */
|
||||
#define RTEMS_RTL_OBJ_SECT_ZERO (1 << 13) /**< Section is preset to zero. */
|
||||
#define RTEMS_RTL_OBJ_SECT_CTOR (1 << 14) /**< Section contains constructors. */
|
||||
#define RTEMS_RTL_OBJ_SECT_DTOR (1 << 15) /**< Section contains destructors. */
|
||||
#define RTEMS_RTL_OBJ_SECT_LINK (1 << 14) /**< Section is link-ordered. */
|
||||
#define RTEMS_RTL_OBJ_SECT_CTOR (1 << 15) /**< Section contains constructors. */
|
||||
#define RTEMS_RTL_OBJ_SECT_DTOR (1 << 16) /**< Section contains destructors. */
|
||||
#define RTEMS_RTL_OBJ_SECT_LOCD (1 << 17) /**< Section has been located. */
|
||||
|
||||
/**
|
||||
* Section types mask.
|
||||
*/
|
||||
#define RTEMS_RTL_OBJ_SECT_TYPES (RTEMS_RTL_OBJ_SECT_TEXT | \
|
||||
RTEMS_RTL_OBJ_SECT_CONST | \
|
||||
RTEMS_RTL_OBJ_SECT_DATA | \
|
||||
RTEMS_RTL_OBJ_SECT_BSS | \
|
||||
RTEMS_RTL_OBJ_SECT_EH)
|
||||
|
||||
/**
|
||||
* An object file is made up of sections and the can be more than
|
||||
@@ -124,6 +135,7 @@ struct rtems_rtl_obj_sect_s
|
||||
uint32_t flags; /**< The section's flags. */
|
||||
void* base; /**< The base address of the section in
|
||||
* memory. */
|
||||
int load_order; /**< Order we load sections. */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user