diff options
Diffstat (limited to 'arch/mn10300/kernel/module.c')
-rw-r--r-- | arch/mn10300/kernel/module.c | 39 |
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 | ||