diff options
author | Mark Salter <msalter@redhat.com> | 2009-06-17 17:51:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-18 16:10:33 -0400 |
commit | 5ae8606d5746bc84e19018fc3753cc1faf18843f (patch) | |
tree | b90484b42af54c43d9cce4ff089ae3b994b91e3f /arch/mn10300 | |
parent | d2829224619866daf336141b71550e223a198838 (diff) |
MN10300: Add support for new ELF relocs in kernel modules
Add support for new relocs which may show up in MN10300 kernel modules due to
linker relaxation.
Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/mn10300')
-rw-r--r-- | arch/mn10300/include/asm/elf.h | 2 | ||||
-rw-r--r-- | arch/mn10300/kernel/module.c | 39 |
2 files changed, 38 insertions, 3 deletions
diff --git a/arch/mn10300/include/asm/elf.h b/arch/mn10300/include/asm/elf.h index 49105462e6fc..75a70aa9fd6f 100644 --- a/arch/mn10300/include/asm/elf.h +++ b/arch/mn10300/include/asm/elf.h | |||
@@ -28,6 +28,8 @@ | |||
28 | #define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ | 28 | #define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ |
29 | #define R_MN10300_24 9 /* Direct 24 bit. */ | 29 | #define R_MN10300_24 9 /* Direct 24 bit. */ |
30 | #define R_MN10300_RELATIVE 23 /* Adjust by program base. */ | 30 | #define R_MN10300_RELATIVE 23 /* Adjust by program base. */ |
31 | #define R_MN10300_SYM_DIFF 33 /* Adjustment when relaxing. */ | ||
32 | #define R_MN10300_ALIGN 34 /* Alignment requirement. */ | ||
31 | 33 | ||
32 | /* | 34 | /* |
33 | * ELF register definitions.. | 35 | * ELF register definitions.. |
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 | ||