diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-08-11 02:17:52 +0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-08-11 02:17:52 +0400 |
commit | 0b019a41553a919965bb02d07d54e3e6c57a796d (patch) | |
tree | 6e329b4159b440d2aac5200a5c07103fe261c096 /arch/arm/kernel | |
parent | 5f6878b0d22f9b93f9698f88c335007e2a3c3bbc (diff) | |
parent | 054d5c9238f3c577ad51195c3ee7803613f322cc (diff) | |
download | linux-0b019a41553a919965bb02d07d54e3e6c57a796d.tar.xz |
Merge branches 'master' and 'devel' into for-linus
Conflicts:
arch/arm/Kconfig
arch/arm/mm/Kconfig
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/module.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index c628bdf6c430..6b4605893f1e 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -102,7 +102,9 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned long loc; Elf32_Sym *sym; s32 offset; +#ifdef CONFIG_THUMB2_KERNEL u32 upper, lower, sign, j1, j2; +#endif offset = ELF32_R_SYM(rel->r_info); if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { @@ -185,6 +187,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, (offset & 0x0fff); break; +#ifdef CONFIG_THUMB2_KERNEL case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: upper = *(u16 *)loc; @@ -233,9 +236,40 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, *(u16 *)(loc + 2) = (u16)((lower & 0xd000) | (j1 << 13) | (j2 << 11) | ((offset >> 1) & 0x07ff)); + 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; +#endif default: printk(KERN_ERR "%s: unknown relocation: %u\n", |