aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/module.c')
-rw-r--r--arch/arm/kernel/module.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index dab48f27263f..bac03c81489d 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -22,6 +22,7 @@
22 22
23#include <asm/pgtable.h> 23#include <asm/pgtable.h>
24#include <asm/sections.h> 24#include <asm/sections.h>
25#include <asm/unwind.h>
25 26
26#ifdef CONFIG_XIP_KERNEL 27#ifdef CONFIG_XIP_KERNEL
27/* 28/*
@@ -66,6 +67,24 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
66 char *secstrings, 67 char *secstrings,
67 struct module *mod) 68 struct module *mod)
68{ 69{
70#ifdef CONFIG_ARM_UNWIND
71 Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
72
73 for (s = sechdrs; s < sechdrs_end; s++) {
74 if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0)
75 mod->arch.unw_sec_init = s;
76 else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0)
77 mod->arch.unw_sec_devinit = s;
78 else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0)
79 mod->arch.unw_sec_core = s;
80 else if (strcmp(".init.text", secstrings + s->sh_name) == 0)
81 mod->arch.sec_init_text = s;
82 else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0)
83 mod->arch.sec_devinit_text = s;
84 else if (strcmp(".text", secstrings + s->sh_name) == 0)
85 mod->arch.sec_core_text = s;
86 }
87#endif
69 return 0; 88 return 0;
70} 89}
71 90
@@ -104,6 +123,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
104 loc = dstsec->sh_addr + rel->r_offset; 123 loc = dstsec->sh_addr + rel->r_offset;
105 124
106 switch (ELF32_R_TYPE(rel->r_info)) { 125 switch (ELF32_R_TYPE(rel->r_info)) {
126 case R_ARM_NONE:
127 /* ignore */
128 break;
129
107 case R_ARM_ABS32: 130 case R_ARM_ABS32:
108 *(u32 *)loc += sym->st_value; 131 *(u32 *)loc += sym->st_value;
109 break; 132 break;
@@ -132,6 +155,35 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
132 *(u32 *)loc |= offset & 0x00ffffff; 155 *(u32 *)loc |= offset & 0x00ffffff;
133 break; 156 break;
134 157
158 case R_ARM_V4BX:
159 /* Preserve Rm and the condition code. Alter
160 * other bits to re-code instruction as
161 * MOV PC,Rm.
162 */
163 *(u32 *)loc &= 0xf000000f;
164 *(u32 *)loc |= 0x01a0f000;
165 break;
166
167 case R_ARM_PREL31:
168 offset = *(u32 *)loc + sym->st_value - loc;
169 *(u32 *)loc = offset & 0x7fffffff;
170 break;
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
135 default: 187 default:
136 printk(KERN_ERR "%s: unknown relocation: %u\n", 188 printk(KERN_ERR "%s: unknown relocation: %u\n",
137 module->name, ELF32_R_TYPE(rel->r_info)); 189 module->name, ELF32_R_TYPE(rel->r_info));
@@ -150,14 +202,50 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
150 return -ENOEXEC; 202 return -ENOEXEC;
151} 203}
152 204
205#ifdef CONFIG_ARM_UNWIND
206static void register_unwind_tables(struct module *mod)
207{
208 if (mod->arch.unw_sec_init && mod->arch.sec_init_text)
209 mod->arch.unwind_init =
210 unwind_table_add(mod->arch.unw_sec_init->sh_addr,
211 mod->arch.unw_sec_init->sh_size,
212 mod->arch.sec_init_text->sh_addr,
213 mod->arch.sec_init_text->sh_size);
214 if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text)
215 mod->arch.unwind_devinit =
216 unwind_table_add(mod->arch.unw_sec_devinit->sh_addr,
217 mod->arch.unw_sec_devinit->sh_size,
218 mod->arch.sec_devinit_text->sh_addr,
219 mod->arch.sec_devinit_text->sh_size);
220 if (mod->arch.unw_sec_core && mod->arch.sec_core_text)
221 mod->arch.unwind_core =
222 unwind_table_add(mod->arch.unw_sec_core->sh_addr,
223 mod->arch.unw_sec_core->sh_size,
224 mod->arch.sec_core_text->sh_addr,
225 mod->arch.sec_core_text->sh_size);
226}
227
228static void unregister_unwind_tables(struct module *mod)
229{
230 unwind_table_del(mod->arch.unwind_init);
231 unwind_table_del(mod->arch.unwind_devinit);
232 unwind_table_del(mod->arch.unwind_core);
233}
234#else
235static inline void register_unwind_tables(struct module *mod) { }
236static inline void unregister_unwind_tables(struct module *mod) { }
237#endif
238
153int 239int
154module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, 240module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
155 struct module *module) 241 struct module *module)
156{ 242{
243 register_unwind_tables(module);
157 return 0; 244 return 0;
158} 245}
159 246
160void 247void
161module_arch_cleanup(struct module *mod) 248module_arch_cleanup(struct module *mod)
162{ 249{
250 unregister_unwind_tables(mod);
163} 251}