From 0b41675971c9952d44f8272cd38e830f25c1af41 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 28 Apr 2020 13:58:20 +1000 Subject: libdl/mips: Fix MIPS16hi/lo relocation support. This patch is an updated version from: https://lists.rtems.org/pipermail/users/2016-January/029740.html Closes #3693 --- cpukit/libdl/rtl-mdreloc-mips.c | 69 +++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 24 deletions(-) (limited to 'cpukit/libdl') diff --git a/cpukit/libdl/rtl-mdreloc-mips.c b/cpukit/libdl/rtl-mdreloc-mips.c index c37804880f..d96f1503e6 100644 --- a/cpukit/libdl/rtl-mdreloc-mips.c +++ b/cpukit/libdl/rtl-mdreloc-mips.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -119,6 +120,14 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj* obj, return rtems_rtl_elf_rel_no_error; } +#define RTEMS_RTL_MIPS_HI16_MAX (128) + +static struct { + Elf_Addr* where_hi16; + Elf_Addr ahl; +} mips_hi16_list[RTEMS_RTL_MIPS_HI16_MAX]; +static size_t mips_hi16_list_cnt; + /* * 1. _gp_disp symbol are not considered in this file. * 2. There is a local/external column; @@ -136,15 +145,13 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, const Elf_Word symvalue) { Elf_Addr *where; - Elf_Word tmp; + Elf_Word tmp; Elf_Word addend = (Elf_Word)0; Elf_Word local = 0; + Elf_Addr *where_hi16; + Elf_Addr ahl; uint32_t t; - - static Elf_Addr *where_hi16; - static Elf_Addr ahl; - where = (Elf_Addr *)(sect->base + rel->r_offset); addend = *where; @@ -205,14 +212,19 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, *where |= tmp & 0x03ffffff; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: R_MIPS_26 local=%lu @ %p in %s\n", + printf ("rtl: R_MIPS_26 local=%" PRIu32 " @ %p in %s\n", local, (void *)*(where), rtems_rtl_obj_oname (obj)); break; case R_TYPE(HI16): - ahl = addend << 16; - where_hi16 = where; - + if (mips_hi16_list_cnt >= RTEMS_RTL_MIPS_HI16_MAX) { + rtems_rtl_set_error (ENOMEM, + "%s: too many MIPS_HI16 relocs", sect->name); + return false; + } + mips_hi16_list[mips_hi16_list_cnt].where_hi16 = where; + mips_hi16_list[mips_hi16_list_cnt].ahl = addend << 16; + ++mips_hi16_list_cnt; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: R_MIPS_HI16 %p @ %p in %s\n", @@ -220,26 +232,35 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, break; case R_TYPE(LO16): - //ahl += (int16_t)addend; - t = ahl + (int16_t)addend; + t = (int16_t) addend; tmp = symvalue; - if (tmp == 0) + if (tmp == 0) { + rtems_rtl_set_error (EINVAL, + "%s: symvalue is 0 in MIPS_LO16", sect->name); return rtems_rtl_elf_rel_failure; + } + /* reloc low part */ addend &= 0xffff0000; addend |= (uint16_t)(t + tmp); *where = addend; - if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf("*where %lx where %p\n", *where, where); - - addend = *where_hi16; - addend &= 0xffff0000; - addend |= ((t + tmp) - (int16_t)(t + tmp)) >> 16; - *where_hi16 = addend; - - if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf("*where_hi %lx where_hi %p\n", *where_hi16, where_hi16); + if (rtems_rtl_trace(RTEMS_RTL_TRACE_RELOC)) + printf("*where %x where %p\n", *where, where); + + /* reloc hi parts */ + while (mips_hi16_list_cnt != 0) { + --mips_hi16_list_cnt; + ahl = mips_hi16_list[mips_hi16_list_cnt].ahl; + where_hi16 = mips_hi16_list[mips_hi16_list_cnt].where_hi16; + addend = *(where_hi16); + addend &= 0xffff0000; + addend |= ((ahl + t + tmp) - (int16_t) (ahl + t + tmp)) >> 16; + *(where_hi16) = addend; + if (rtems_rtl_trace(RTEMS_RTL_TRACE_RELOC)) + printf("*where_hi %x where_hi %p ahl=%08x\n", + *(where_hi16), where_hi16, ahl); + } if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: R_MIPS_LO16 %p @ %p in %s\n", @@ -266,12 +287,12 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, break; default: - printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " + printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p, " "contents = %p\n", ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), (void *)rel->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, - "%s: Unsupported relocation type %ld " + "%s: Unsupported relocation type %" PRIu32 "in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); return rtems_rtl_elf_rel_failure; -- cgit v1.2.3