Go ahead On 03.02.2015 22:30, Leif Lindholm wrote: > 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 > --- > grub-core/kern/arm/dl.c | 15 +++++++++++++++ > grub-core/kern/arm/dl_helper.c | 39 +++++++++++++++++++++++++++++++++++++++ > include/grub/arm/reloc.h | 5 +++++ > 3 files changed, 59 insertions(+) > > diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c > index 57cac2e..5cbd65e 100644 > --- a/grub-core/kern/arm/dl.c > +++ b/grub-core/kern/arm/dl.c > @@ -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 */ > diff --git a/grub-core/kern/arm/dl_helper.c b/grub-core/kern/arm/dl_helper.c > index 5721939..8a72632 100644 > --- a/grub-core/kern/arm/dl_helper.c > +++ b/grub-core/kern/arm/dl_helper.c > @@ -25,6 +25,20 @@ > #include > #include > > +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 > * > @@ -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); > +} > diff --git a/include/grub/arm/reloc.h b/include/grub/arm/reloc.h > index b938037..ae92e21 100644 > --- a/include/grub/arm/reloc.h > +++ b/include/grub/arm/reloc.h > @@ -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 >