diff options
author | Paul Gortmaker <paul.gortmaker@gmail.com> | 2009-05-07 11:18:40 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-05-07 12:21:01 -0400 |
commit | ae51e609843f7d0aaeb1c2ad9f89d252a4899885 (patch) | |
tree | af632106715c1c3db9c974fdecf6903e86eef1ed /arch | |
parent | a029b706d3b2d3a139bdeae84131d9a0f35f6478 (diff) |
[ARM] 5507/1: support R_ARM_MOVW_ABS_NC and MOVT_ABS relocation types
From: Bruce Ashfield <bruce.ashfield@windriver.com>
To fully support the armv7-a instruction set/optimizations, support
for the R_ARM_MOVW_ABS_NC and R_ARM_MOVT_ABS relocation types is
required.
The MOVW and MOVT are both load-immediate instructions, MOVW loads 16
bits into the bottom half of a register, and MOVT loads 16 bits into the
top half of a register.
The relocation information for these instructions has a full 32 bit
value, plus an addend which is stored in the 16 immediate bits in the
instruction itself. The immediate bits in the instruction are not
contiguous (the register # splits it into a 4 bit and 12 bit value),
so the addend has to be extracted accordingly and added to the value.
The value is then split and put into the instruction; a MOVW uses the
bottom 16 bits of the value, and a MOVT uses the top 16 bits.
Signed-off-by: David Borman <david.borman@windriver.com>
Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/elf.h | 16 | ||||
-rw-r--r-- | arch/arm/kernel/module.c | 15 |
2 files changed, 24 insertions, 7 deletions
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index d7da19bcf928..c207504de84d 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h | |||
@@ -45,13 +45,15 @@ typedef struct user_fp elf_fpregset_t; | |||
45 | #define EF_ARM_HASENTRY 0x00000002 /* All */ | 45 | #define EF_ARM_HASENTRY 0x00000002 /* All */ |
46 | #define EF_ARM_RELEXEC 0x00000001 /* All */ | 46 | #define EF_ARM_RELEXEC 0x00000001 /* All */ |
47 | 47 | ||
48 | #define R_ARM_NONE 0 | 48 | #define R_ARM_NONE 0 |
49 | #define R_ARM_PC24 1 | 49 | #define R_ARM_PC24 1 |
50 | #define R_ARM_ABS32 2 | 50 | #define R_ARM_ABS32 2 |
51 | #define R_ARM_CALL 28 | 51 | #define R_ARM_CALL 28 |
52 | #define R_ARM_JUMP24 29 | 52 | #define R_ARM_JUMP24 29 |
53 | #define R_ARM_V4BX 40 | 53 | #define R_ARM_V4BX 40 |
54 | #define R_ARM_PREL31 42 | 54 | #define R_ARM_PREL31 42 |
55 | #define R_ARM_MOVW_ABS_NC 43 | ||
56 | #define R_ARM_MOVT_ABS 44 | ||
55 | 57 | ||
56 | /* | 58 | /* |
57 | * These are used to set parameters in the core dumps. | 59 | * These are used to set parameters in the core dumps. |
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index d1731e39b496..bac03c81489d 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c | |||
@@ -169,6 +169,21 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
169 | *(u32 *)loc = offset & 0x7fffffff; | 169 | *(u32 *)loc = offset & 0x7fffffff; |
170 | break; | 170 | break; |
171 | 171 | ||
172 | case R_ARM_MOVW_ABS_NC: | ||
173 | case R_ARM_MOVT_ABS: | ||
174 | offset = *(u32 *)loc; | ||
175 | offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff); | ||
176 | offset = (offset ^ 0x8000) - 0x8000; | ||
177 | |||
178 | offset += sym->st_value; | ||
179 | if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS) | ||
180 | offset >>= 16; | ||
181 | |||
182 | *(u32 *)loc &= 0xfff0f000; | ||
183 | *(u32 *)loc |= ((offset & 0xf000) << 4) | | ||
184 | (offset & 0x0fff); | ||
185 | break; | ||
186 | |||
172 | default: | 187 | default: |
173 | printk(KERN_ERR "%s: unknown relocation: %u\n", | 188 | printk(KERN_ERR "%s: unknown relocation: %u\n", |
174 | module->name, ELF32_R_TYPE(rel->r_info)); | 189 | module->name, ELF32_R_TYPE(rel->r_info)); |