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
This commit is contained in:
Chris Johns
2020-04-28 13:58:20 +10:00
parent 396e98305e
commit 0b41675971

View File

@@ -1,6 +1,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -119,6 +120,14 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj* obj,
return rtems_rtl_elf_rel_no_error; 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. * 1. _gp_disp symbol are not considered in this file.
* 2. There is a local/external column; * 2. There is a local/external column;
@@ -136,15 +145,13 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj,
const Elf_Word symvalue) const Elf_Word symvalue)
{ {
Elf_Addr *where; Elf_Addr *where;
Elf_Word tmp; Elf_Word tmp;
Elf_Word addend = (Elf_Word)0; Elf_Word addend = (Elf_Word)0;
Elf_Word local = 0; Elf_Word local = 0;
Elf_Addr *where_hi16;
Elf_Addr ahl;
uint32_t t; uint32_t t;
static Elf_Addr *where_hi16;
static Elf_Addr ahl;
where = (Elf_Addr *)(sect->base + rel->r_offset); where = (Elf_Addr *)(sect->base + rel->r_offset);
addend = *where; addend = *where;
@@ -205,14 +212,19 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj,
*where |= tmp & 0x03ffffff; *where |= tmp & 0x03ffffff;
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) 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)); local, (void *)*(where), rtems_rtl_obj_oname (obj));
break; break;
case R_TYPE(HI16): case R_TYPE(HI16):
ahl = addend << 16; if (mips_hi16_list_cnt >= RTEMS_RTL_MIPS_HI16_MAX) {
where_hi16 = where; 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)) if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
printf ("rtl: R_MIPS_HI16 %p @ %p in %s\n", printf ("rtl: R_MIPS_HI16 %p @ %p in %s\n",
@@ -220,26 +232,35 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj,
break; break;
case R_TYPE(LO16): case R_TYPE(LO16):
//ahl += (int16_t)addend; t = (int16_t) addend;
t = ahl + (int16_t)addend;
tmp = symvalue; 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; return rtems_rtl_elf_rel_failure;
}
/* reloc low part */
addend &= 0xffff0000; addend &= 0xffff0000;
addend |= (uint16_t)(t + tmp); addend |= (uint16_t)(t + tmp);
*where = addend; *where = addend;
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) if (rtems_rtl_trace(RTEMS_RTL_TRACE_RELOC))
printf("*where %lx where %p\n", *where, where); printf("*where %x where %p\n", *where, where);
addend = *where_hi16; /* reloc hi parts */
addend &= 0xffff0000; while (mips_hi16_list_cnt != 0) {
addend |= ((t + tmp) - (int16_t)(t + tmp)) >> 16; --mips_hi16_list_cnt;
*where_hi16 = addend; ahl = mips_hi16_list[mips_hi16_list_cnt].ahl;
where_hi16 = mips_hi16_list[mips_hi16_list_cnt].where_hi16;
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) addend = *(where_hi16);
printf("*where_hi %lx where_hi %p\n", *where_hi16, 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)) if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
printf ("rtl: R_MIPS_LO16 %p @ %p in %s\n", printf ("rtl: R_MIPS_LO16 %p @ %p in %s\n",
@@ -266,12 +287,12 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj,
break; break;
default: default:
printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p, "
"contents = %p\n", "contents = %p\n",
ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
(void *)rel->r_offset, (void *)*where); (void *)rel->r_offset, (void *)*where);
rtems_rtl_set_error (EINVAL, rtems_rtl_set_error (EINVAL,
"%s: Unsupported relocation type %ld " "%s: Unsupported relocation type %" PRIu32
"in non-PLT relocations", "in non-PLT relocations",
sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
return rtems_rtl_elf_rel_failure; return rtems_rtl_elf_rel_failure;