Skip to content

Commit

Permalink
arm: implement additional relocations generated by gcc 4.9 at -O3
Browse files Browse the repository at this point in the history
GCC 4.9 also generates R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_ABS,
as an alternative to ABS32.

Signed-off-by: Leif Lindholm <[email protected]>
  • Loading branch information
Leif Lindholm committed Feb 3, 2015
1 parent 016875d commit c0f529e
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
15 changes: 15 additions & 0 deletions grub-core/kern/arm/dl.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
*/
case R_ARM_V4BX:
break;
case R_ARM_THM_MOVW_ABS_NC:
case R_ARM_THM_MOVT_ABS:
{
grub_uint32_t offset;
offset = grub_arm_thm_movw_movt_get_value((grub_uint16_t *) target);
offset += sym_addr;

if (ELF_R_TYPE (rel->r_info) == R_ARM_THM_MOVT_ABS)
offset >>= 16;
else
offset &= 0xffff;

grub_arm_thm_movw_movt_set_value((grub_uint16_t *) target, offset);
}
break;
case R_ARM_THM_JUMP19:
{
/* Thumb instructions can be 16-bit aligned */
Expand Down
39 changes: 39 additions & 0 deletions grub-core/kern/arm/dl_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@
#include <grub/i18n.h>
#include <grub/arm/reloc.h>

static inline grub_uint32_t
thumb_get_instruction_word(grub_uint16_t *target)
{
/* Extract instruction word in alignment-safe manner */
return grub_le_to_cpu16 ((*target)) << 16 | grub_le_to_cpu16 (*(target + 1));
}

static inline void
thumb_set_instruction_word(grub_uint16_t *target, grub_uint32_t insword)
{
*target = grub_cpu_to_le16 (insword >> 16);
*(target + 1) = grub_cpu_to_le16 (insword & 0xffff);
}

/*
* R_ARM_ABS32
*
Expand Down Expand Up @@ -214,3 +228,28 @@ grub_arm_jump24_set_offset (grub_uint32_t *target,

*target = grub_cpu_to_le32 (insword);
}

grub_uint16_t
grub_arm_thm_movw_movt_get_value (grub_uint16_t *target)
{
grub_uint32_t insword;

insword = thumb_get_instruction_word (target);

return ((insword & 0xf0000) >> 4) | ((insword & 0x04000000) >> 15) | \
((insword & 0x7000) >> 4) | (insword & 0xff);
}

void
grub_arm_thm_movw_movt_set_value (grub_uint16_t *target, grub_uint16_t value)
{
grub_uint32_t insword;

insword = thumb_get_instruction_word (target);
insword &= 0xfbf08f00;

insword |= ((value & 0xf000) << 4) | ((value & 0x0800) << 15) | \
((value & 0x0700) << 4) | (value & 0xff);

thumb_set_instruction_word (target, insword);
}
5 changes: 5 additions & 0 deletions include/grub/arm/reloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ void
grub_arm_jump24_set_offset (grub_uint32_t *target,
grub_int32_t offset);

grub_uint16_t
grub_arm_thm_movw_movt_get_value (grub_uint16_t *target);
void
grub_arm_thm_movw_movt_set_value (grub_uint16_t *target, grub_uint16_t value);

#endif

0 comments on commit c0f529e

Please sign in to comment.