diff options
author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2014-11-24 10:45:12 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-02-23 09:43:58 -0500 |
commit | 2b8514d0a792857b0826fe6b7c3b941cdb59a9c3 (patch) | |
tree | 2816476662440ce74a7d8336692dca8748746de3 | |
parent | c517d838eb7d07bbe9507871fab3931deccff539 (diff) |
ARM: 8219/1: handle interworking and out-of-range relocations separately
Currently, interworking calls on module boundaries are not supported,
and are handled by the same error handling code path as non-interworking
calls whose targets are simply out of range.
Before modifying the handling of those out-of-range jump and call
relocations in a subsequent patch, move the handling of interworking
restrictions out of it.
Acked-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/kernel/module.c | 38 |
1 files changed, 24 insertions, 14 deletions
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 2e11961f65ae..af791f4a6205 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c | |||
@@ -98,14 +98,19 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
98 | case R_ARM_PC24: | 98 | case R_ARM_PC24: |
99 | case R_ARM_CALL: | 99 | case R_ARM_CALL: |
100 | case R_ARM_JUMP24: | 100 | case R_ARM_JUMP24: |
101 | if (sym->st_value & 3) { | ||
102 | pr_err("%s: section %u reloc %u sym '%s': unsupported interworking call (ARM -> Thumb)\n", | ||
103 | module->name, relindex, i, symname); | ||
104 | return -ENOEXEC; | ||
105 | } | ||
106 | |||
101 | offset = __mem_to_opcode_arm(*(u32 *)loc); | 107 | offset = __mem_to_opcode_arm(*(u32 *)loc); |
102 | offset = (offset & 0x00ffffff) << 2; | 108 | offset = (offset & 0x00ffffff) << 2; |
103 | if (offset & 0x02000000) | 109 | if (offset & 0x02000000) |
104 | offset -= 0x04000000; | 110 | offset -= 0x04000000; |
105 | 111 | ||
106 | offset += sym->st_value - loc; | 112 | offset += sym->st_value - loc; |
107 | if (offset & 3 || | 113 | if (offset <= (s32)0xfe000000 || |
108 | offset <= (s32)0xfe000000 || | ||
109 | offset >= (s32)0x02000000) { | 114 | offset >= (s32)0x02000000) { |
110 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", | 115 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
111 | module->name, relindex, i, symname, | 116 | module->name, relindex, i, symname, |
@@ -155,6 +160,22 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
155 | #ifdef CONFIG_THUMB2_KERNEL | 160 | #ifdef CONFIG_THUMB2_KERNEL |
156 | case R_ARM_THM_CALL: | 161 | case R_ARM_THM_CALL: |
157 | case R_ARM_THM_JUMP24: | 162 | case R_ARM_THM_JUMP24: |
163 | /* | ||
164 | * For function symbols, only Thumb addresses are | ||
165 | * allowed (no interworking). | ||
166 | * | ||
167 | * For non-function symbols, the destination | ||
168 | * has no specific ARM/Thumb disposition, so | ||
169 | * the branch is resolved under the assumption | ||
170 | * that interworking is not required. | ||
171 | */ | ||
172 | if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && | ||
173 | !(sym->st_value & 1)) { | ||
174 | pr_err("%s: section %u reloc %u sym '%s': unsupported interworking call (Thumb -> ARM)\n", | ||
175 | module->name, relindex, i, symname); | ||
176 | return -ENOEXEC; | ||
177 | } | ||
178 | |||
158 | upper = __mem_to_opcode_thumb16(*(u16 *)loc); | 179 | upper = __mem_to_opcode_thumb16(*(u16 *)loc); |
159 | lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2)); | 180 | lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2)); |
160 | 181 | ||
@@ -182,18 +203,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
182 | offset -= 0x02000000; | 203 | offset -= 0x02000000; |
183 | offset += sym->st_value - loc; | 204 | offset += sym->st_value - loc; |
184 | 205 | ||
185 | /* | 206 | if (offset <= (s32)0xff000000 || |
186 | * For function symbols, only Thumb addresses are | ||
187 | * allowed (no interworking). | ||
188 | * | ||
189 | * For non-function symbols, the destination | ||
190 | * has no specific ARM/Thumb disposition, so | ||
191 | * the branch is resolved under the assumption | ||
192 | * that interworking is not required. | ||
193 | */ | ||
194 | if ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC && | ||
195 | !(offset & 1)) || | ||
196 | offset <= (s32)0xff000000 || | ||
197 | offset >= (s32)0x01000000) { | 207 | offset >= (s32)0x01000000) { |
198 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", | 208 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
199 | module->name, relindex, i, symname, | 209 | module->name, relindex, i, symname, |