ARM: 6189/1: Add support for the MOVW/MOVT relocations in Thumb-2
authorCatalin Marinas <catalin.marinas@arm.com>
Mon, 21 Jun 2010 14:10:37 +0000 (15:10 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 5 Aug 2010 09:35:46 +0000 (10:35 +0100)
The patch adds handling case for the R_ARM_THM_MOVW_ABS_NC and
R_ARM_THM_MOVT_ABS relocations in arch/arm/kernel/module.c. Such
relocations may appear in Thumb-2 compiled kernel modules.

Reported-by: Kyungmin Park <kmpark@infradead.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/include/asm/elf.h
arch/arm/kernel/module.c

index 6750b8e..5747a8b 100644 (file)
@@ -59,6 +59,8 @@ typedef struct user_fp elf_fpregset_t;
 
 #define R_ARM_THM_CALL         10
 #define R_ARM_THM_JUMP24       30
+#define R_ARM_THM_MOVW_ABS_NC  47
+#define R_ARM_THM_MOVT_ABS     48
 
 /*
  * These are used to set parameters in the core dumps.
index c628bdf..ae3c804 100644 (file)
@@ -237,6 +237,38 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                        lower = *(u16 *)(loc + 2);
                        break;
 
+               case R_ARM_THM_MOVW_ABS_NC:
+               case R_ARM_THM_MOVT_ABS:
+                       upper = *(u16 *)loc;
+                       lower = *(u16 *)(loc + 2);
+
+                       /*
+                        * MOVT/MOVW instructions encoding in Thumb-2:
+                        *
+                        * i    = upper[10]
+                        * imm4 = upper[3:0]
+                        * imm3 = lower[14:12]
+                        * imm8 = lower[7:0]
+                        *
+                        * imm16 = imm4:i:imm3:imm8
+                        */
+                       offset = ((upper & 0x000f) << 12) |
+                               ((upper & 0x0400) << 1) |
+                               ((lower & 0x7000) >> 4) | (lower & 0x00ff);
+                       offset = (offset ^ 0x8000) - 0x8000;
+                       offset += sym->st_value;
+
+                       if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS)
+                               offset >>= 16;
+
+                       *(u16 *)loc = (u16)((upper & 0xfbf0) |
+                                           ((offset & 0xf000) >> 12) |
+                                           ((offset & 0x0800) >> 1));
+                       *(u16 *)(loc + 2) = (u16)((lower & 0x8f00) |
+                                                 ((offset & 0x0700) << 4) |
+                                                 (offset & 0x00ff));
+                       break;
+
                default:
                        printk(KERN_ERR "%s: unknown relocation: %u\n",
                               module->name, ELF32_R_TYPE(rel->r_info));