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.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index dab48f27263f..d1731e39b496 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,20 @@ 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
135 default: 172 default:
136 printk(KERN_ERR "%s: unknown relocation: %u\n", 173 printk(KERN_ERR "%s: unknown relocation: %u\n",
137 module->name, ELF32_R_TYPE(rel->r_info)); 174 module->name, ELF32_R_TYPE(rel->r_info));
@@ -150,14 +187,50 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
150 return -ENOEXEC; 187 return -ENOEXEC;
151} 188}
152 189
190#ifdef CONFIG_ARM_UNWIND
191static void register_unwind_tables(struct module *mod)
192{
193 if (mod->arch.unw_sec_init && mod->arch.sec_init_text)
194 mod->arch.unwind_init =
195 unwind_table_add(mod->arch.unw_sec_init->sh_addr,
196 mod->arch.unw_sec_init->sh_size,
197 mod->arch.sec_init_text->sh_addr,
198 mod->arch.sec_init_text->sh_size);
199 if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text)
200 mod->arch.unwind_devinit =
201 unwind_table_add(mod->arch.unw_sec_devinit->sh_addr,
202 mod->arch.unw_sec_devinit->sh_size,
203 mod->arch.sec_devinit_text->sh_addr,
204 mod->arch.sec_devinit_text->sh_size);
205 if (mod->arch.unw_sec_core && mod->arch.sec_core_text)
206 mod->arch.unwind_core =
207 unwind_table_add(mod->arch.unw_sec_core->sh_addr,
208 mod->arch.unw_sec_core->sh_size,
209 mod->arch.sec_core_text->sh_addr,
210 mod->arch.sec_core_text->sh_size);
211}
212
213static void unregister_unwind_tables(struct module *mod)
214{
215 unwind_table_del(mod->arch.unwind_init);
216 unwind_table_del(mod->arch.unwind_devinit);
217 unwind_table_del(mod->arch.unwind_core);
218}
219#else
220static inline void register_unwind_tables(struct module *mod) { }
221static inline void unregister_unwind_tables(struct module *mod) { }
222#endif
223
153int 224int
154module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, 225module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
155 struct module *module) 226 struct module *module)
156{ 227{
228 register_unwind_tables(module);
157 return 0; 229 return 0;
158} 230}
159 231
160void 232void
161module_arch_cleanup(struct module *mod) 233module_arch_cleanup(struct module *mod)
162{ 234{
235 unregister_unwind_tables(mod);
163} 236}