forked from Imagelibrary/rtems
cpukit/libdl/arm: Support BLX relocations that require a trampoline
BLX relocations in Thumb code expect the target to be ARM code. This means that the trampoline must be generated in ARM mode.
This commit is contained in:
committed by
Kinsey Moore
parent
689e9986cd
commit
c978b63c3a
@@ -70,6 +70,23 @@ sign_extend31(Elf_Addr val)
|
|||||||
return 0x7fffffff & val;
|
return 0x7fffffff & val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
set_arm_veneer(void* trampoline, Elf_Addr target)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* ARM mode:
|
||||||
|
* ldr pc, [pc, #-4]
|
||||||
|
*/
|
||||||
|
uint32_t* tramp = (uint32_t*) trampoline;
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
*tramp++ = 0xe51ff004;
|
||||||
|
#else
|
||||||
|
*tramp++ = 0xe51ff004; /* not tested */
|
||||||
|
#endif
|
||||||
|
*tramp++ = (uint32_t) target;
|
||||||
|
return tramp;
|
||||||
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
set_veneer(void* trampoline, Elf_Addr target)
|
set_veneer(void* trampoline, Elf_Addr target)
|
||||||
{
|
{
|
||||||
@@ -79,26 +96,19 @@ set_veneer(void* trampoline, Elf_Addr target)
|
|||||||
* Thumb mode:
|
* Thumb mode:
|
||||||
* ldr.w pc, [pc]
|
* ldr.w pc, [pc]
|
||||||
*
|
*
|
||||||
* ARM mode:
|
|
||||||
* ldr pc, [pc, #-4]
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
uint32_t* tramp = (uint32_t*) trampoline;
|
|
||||||
#if defined(__thumb__)
|
#if defined(__thumb__)
|
||||||
|
uint32_t* tramp = (uint32_t*) trampoline;
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
*tramp++ = 0xf000f8df;
|
*tramp++ = 0xf000f8df;
|
||||||
#else
|
#else
|
||||||
*tramp++ = 0xf8dff000; /* not tested */
|
*tramp++ = 0xf8dff000; /* not tested */
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
||||||
*tramp++ = 0xe51ff004;
|
|
||||||
#else
|
|
||||||
*tramp++ = 0xe51ff004; /* not tested */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
*tramp++ = (uint32_t) target;
|
*tramp++ = (uint32_t) target;
|
||||||
return tramp;
|
return tramp;
|
||||||
|
#else
|
||||||
|
return set_arm_veneer(trampoline, target);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
@@ -443,16 +453,11 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj* obj,
|
|||||||
addend = (tmp | ((sign ? 0 : 1) << 24)) - (1 << 24);
|
addend = (tmp | ((sign ? 0 : 1) << 24)) - (1 << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isThumb(symvalue)) ;/*Thumb to Thumb call, nothing to care */
|
if (isThumb(symvalue) == false
|
||||||
else {
|
&& ELF_R_TYPE(rel->r_info) != R_TYPE(THM_JUMP24)) {
|
||||||
if (ELF_R_TYPE(rel->r_info) == R_TYPE(THM_JUMP24)) {
|
|
||||||
tmp = (tmp + 2) & ~3; /* aligned to 4 bytes only for JUMP24 */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* THM_CALL bl-->blx */
|
/* THM_CALL bl-->blx */
|
||||||
lower_insn &= ~(1<<12);
|
lower_insn &= ~(1<<12);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (parsing && sect->base == 0) {
|
if (parsing && sect->base == 0) {
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||||
@@ -461,7 +466,15 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj* obj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tmp = symvalue + addend;
|
tmp = symvalue + addend;
|
||||||
|
if (isThumb(symvalue)) {
|
||||||
tmp = tmp - (Elf_Addr)where;
|
tmp = tmp - (Elf_Addr)where;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* where[1:0] are set to 0 for ARM-targeted relocations because the jump
|
||||||
|
* offset[1:0] are also 0
|
||||||
|
*/
|
||||||
|
tmp = tmp - (Elf_Addr)((uintptr_t)where & 0xfffffffc);
|
||||||
|
}
|
||||||
|
|
||||||
if (isThumb(symvalue) == false && ELF_R_TYPE(rel->r_info) == R_TYPE(THM_JUMP24)) {
|
if (isThumb(symvalue) == false && ELF_R_TYPE(rel->r_info) == R_TYPE(THM_JUMP24)) {
|
||||||
Elf_Word tramp_addr;
|
Elf_Word tramp_addr;
|
||||||
@@ -486,6 +499,7 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj* obj,
|
|||||||
|
|
||||||
|
|
||||||
tmp = tramp_addr + addend;
|
tmp = tramp_addr + addend;
|
||||||
|
/* This targets a thumb trampoline, so no need to adjust the PC */
|
||||||
tmp = tmp - (Elf_Addr)where;
|
tmp = tmp - (Elf_Addr)where;
|
||||||
} else if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) {
|
} else if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) {
|
||||||
Elf_Word tramp_addr;
|
Elf_Word tramp_addr;
|
||||||
@@ -506,11 +520,24 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj* obj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
|
tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
|
||||||
obj->tramp_brk = set_veneer(obj->tramp_brk, symvalue);
|
|
||||||
|
|
||||||
|
|
||||||
tmp = tramp_addr + addend;
|
tmp = tramp_addr + addend;
|
||||||
|
if (isThumb(symvalue)) {
|
||||||
|
obj->tramp_brk = set_veneer(obj->tramp_brk, symvalue);
|
||||||
tmp = tmp - (Elf_Addr)where;
|
tmp = tmp - (Elf_Addr)where;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* The B[L]X expects ARM code at the target. Align tramp_brk as
|
||||||
|
* necessary.
|
||||||
|
*/
|
||||||
|
obj->tramp_brk = (void *)RTEMS_ALIGN_UP((uintptr_t)obj->tramp_brk, 4);
|
||||||
|
tramp_addr = (Elf_Addr) obj->tramp_brk;
|
||||||
|
obj->tramp_brk = set_arm_veneer(obj->tramp_brk, symvalue);
|
||||||
|
/*
|
||||||
|
* where[1:0] are set to 0 for ARM-targeted relocations because the jump
|
||||||
|
* offset[1:0] are also 0
|
||||||
|
*/
|
||||||
|
tmp = tmp - (Elf_Addr)((uintptr_t)where & 0xfffffffc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parsing) {
|
if (!parsing) {
|
||||||
|
|||||||
Reference in New Issue
Block a user