aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/kernel/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mn10300/kernel/module.c')
-rw-r--r--arch/mn10300/kernel/module.c39
1 files changed, 36 insertions, 3 deletions
diff --git a/arch/mn10300/kernel/module.c b/arch/mn10300/kernel/module.c
index 4fa0e3648d8e..6aea7fd76993 100644
--- a/arch/mn10300/kernel/module.c
+++ b/arch/mn10300/kernel/module.c
@@ -1,6 +1,6 @@
1/* MN10300 Kernel module helper routines 1/* MN10300 Kernel module helper routines
2 * 2 *
3 * Copyright (C) 2007, 2008 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2007, 2008, 2009 Red Hat, Inc. All Rights Reserved.
4 * Written by Mark Salter (msalter@redhat.com) 4 * Written by Mark Salter (msalter@redhat.com)
5 * - Derived from arch/i386/kernel/module.c 5 * - Derived from arch/i386/kernel/module.c
6 * 6 *
@@ -103,10 +103,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
103 unsigned int relsec, 103 unsigned int relsec,
104 struct module *me) 104 struct module *me)
105{ 105{
106 unsigned int i; 106 unsigned int i, sym_diff_seen = 0;
107 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; 107 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
108 Elf32_Sym *sym; 108 Elf32_Sym *sym;
109 Elf32_Addr relocation; 109 Elf32_Addr relocation, sym_diff_val = 0;
110 uint8_t *location; 110 uint8_t *location;
111 uint32_t value; 111 uint32_t value;
112 112
@@ -126,6 +126,22 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
126 /* this is the adjustment to be made */ 126 /* this is the adjustment to be made */
127 relocation = sym->st_value + rel[i].r_addend; 127 relocation = sym->st_value + rel[i].r_addend;
128 128
129 if (sym_diff_seen) {
130 switch (ELF32_R_TYPE(rel[i].r_info)) {
131 case R_MN10300_32:
132 case R_MN10300_24:
133 case R_MN10300_16:
134 case R_MN10300_8:
135 relocation -= sym_diff_val;
136 sym_diff_seen = 0;
137 break;
138 default:
139 printk(KERN_ERR "module %s: Unexpected SYM_DIFF relocation: %u\n",
140 me->name, ELF32_R_TYPE(rel[i].r_info));
141 return -ENOEXEC;
142 }
143 }
144
129 switch (ELF32_R_TYPE(rel[i].r_info)) { 145 switch (ELF32_R_TYPE(rel[i].r_info)) {
130 /* for the first four relocation types, we simply 146 /* for the first four relocation types, we simply
131 * store the adjustment at the location given */ 147 * store the adjustment at the location given */
@@ -157,12 +173,29 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
157 *location = relocation - (uint32_t) location; 173 *location = relocation - (uint32_t) location;
158 break; 174 break;
159 175
176 case R_MN10300_SYM_DIFF:
177 /* This is used to adjust the next reloc as required
178 * by relaxation. */
179 sym_diff_seen = 1;
180 sym_diff_val = sym->st_value;
181 break;
182
183 case R_MN10300_ALIGN:
184 /* Just ignore the ALIGN relocs.
185 * Only interesting if kernel performed relaxation. */
186 continue;
187
160 default: 188 default:
161 printk(KERN_ERR "module %s: Unknown relocation: %u\n", 189 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
162 me->name, ELF32_R_TYPE(rel[i].r_info)); 190 me->name, ELF32_R_TYPE(rel[i].r_info));
163 return -ENOEXEC; 191 return -ENOEXEC;
164 } 192 }
165 } 193 }
194 if (sym_diff_seen) {
195 printk(KERN_ERR "module %s: Nothing follows SYM_DIFF relocation: %u\n",
196 me->name, ELF32_R_TYPE(rel[i].r_info));
197 return -ENOEXEC;
198 }
166 return 0; 199 return 0;
167} 200}
168 201