diff options
author | Chris Johns <chrisj@rtems.org> | 2017-03-30 11:06:24 +1100 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2017-03-31 09:00:14 +1100 |
commit | bba48d90bcd343f62b368a510b67bbdb51fb6f0c (patch) | |
tree | 0f7b4fb43aa7a432228d420f7987d7dcf4c6d90c /cpukit/libdl/rtl-obj.c | |
parent | benchmarks/whetstone: Port to RTEMS (diff) | |
download | rtems-bba48d90bcd343f62b368a510b67bbdb51fb6f0c.tar.bz2 |
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
Diffstat (limited to 'cpukit/libdl/rtl-obj.c')
-rw-r--r-- | cpukit/libdl/rtl-obj.c | 159 |
1 files changed, 130 insertions, 29 deletions
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c index b27f28b9a9..bb0bc8d543 100644 --- a/cpukit/libdl/rtl-obj.c +++ b/cpukit/libdl/rtl-obj.c @@ -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); + if (sect->load_order == order) + { + if (!first) + base_offset = rtems_rtl_sect_align (base_offset, sect->alignment); - sect->base = base + base_offset; + first = false; - 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); + sect->base = base + base_offset; - if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD) - { - if (!handler (obj, fd, sect, data)) + 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)) { @@ -780,6 +873,14 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* 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. */ |