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 <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <sys/types.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;
}
#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;
@@ -139,12 +148,10 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj,
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);
printf("*where %x where %p\n", *where, where);
addend = *where_hi16;
/* 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 |= ((t + tmp) - (int16_t)(t + tmp)) >> 16;
*where_hi16 = addend;
addend |= ((ahl + t + tmp) - (int16_t) (ahl + 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);
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;