18 #include <linux/module.h>
19 #include <linux/elf.h>
25 #include <asm/module.h>
42 #define DEBUGP(fmt , ...)
65 0x3d, 0x82, 0x00, 0x00,
66 0x39, 0x8c, 0x00, 0x00,
68 0xf8, 0x41, 0x00, 0x28,
69 0xe9, 0x6c, 0x00, 0x20,
70 0xe8, 0x4c, 0x00, 0x28,
71 0x7d, 0x69, 0x03, 0xa6,
72 0x4e, 0x80, 0x04, 0x20
77 static unsigned int count_relocs(
const Elf64_Rela *rela,
unsigned int num)
79 unsigned int i, r_info, r_addend, _count_relocs;
85 for (i = 0; i < num; i++)
89 r_addend != rela[i].r_addend)) {
98 static int relacmp(
const void *_x,
const void *_y)
121 static void relaswap(
void *_x,
void *_y,
int size)
141 unsigned long relocs = 1;
145 for (i = 1; i < hdr->
e_shnum; i++) {
146 if (sechdrs[i].sh_type ==
SHT_RELA) {
147 DEBUGP(
"Found relocations in section %u\n", i);
148 DEBUGP(
"Ptr: %p. Number: %lu\n",
149 (
void *)sechdrs[i].sh_addr,
157 sort((
void *)sechdrs[i].sh_addr,
161 relocs += count_relocs((
void *)sechdrs[i].sh_addr,
167 #ifdef CONFIG_DYNAMIC_FTRACE
172 DEBUGP(
"Looks like a total of %lu stubs, max\n", relocs);
181 for (end = (
void *)vers + size; vers <
end; vers++)
182 if (vers->
name[0] ==
'.')
187 static void dedotify(
Elf64_Sym *syms,
unsigned int numsyms,
char *strtab)
191 for (i = 1; i < numsyms; i++) {
208 for (i = 1; i < hdr->
e_shnum; i++) {
210 if (
strcmp(secstrings + sechdrs[i].sh_name,
".stubs") == 0)
211 me->arch.stubs_section =
i;
212 else if (
strcmp(secstrings + sechdrs[i].sh_name,
".toc") == 0)
213 me->arch.toc_section =
i;
214 else if (
strcmp(secstrings+sechdrs[i].sh_name,
"__versions")==0)
215 dedotify_versions((
void *)hdr + sechdrs[i].sh_offset,
219 while ((p =
strstr(secstrings + sechdrs[i].sh_name,
".init")))
223 dedotify((
void *)hdr + sechdrs[i].sh_offset,
226 + sechdrs[sechdrs[i].sh_link].sh_offset);
229 if (!me->arch.stubs_section) {
230 printk(
"%s: doesn't contain .stubs.\n", me->
name);
238 if (!me->arch.toc_section)
239 me->arch.toc_section = me->arch.stubs_section;
242 sechdrs[me->arch.stubs_section].
sh_size = get_stubs_size(hdr, sechdrs);
251 return sechdrs[me->arch.toc_section].
sh_addr + 0x8000;
257 #define PPC_LO(v) ((v) & 0xffff)
258 #define PPC_HI(v) (((v) >> 16) & 0xffff)
259 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
262 static inline int create_stub(
Elf64_Shdr *sechdrs,
276 reladdr = (
unsigned long)entry - my_r2(sechdrs, me);
277 if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) {
278 printk(
"%s: Address %p of stub out of range of %p.\n",
279 me->
name, (
void *)reladdr, (
void *)my_r2);
282 DEBUGP(
"Stub %p get data from reladdr %li\n", entry, reladdr);
287 entry->
opd.r2 = opd->
r2;
293 static unsigned long stub_for_addr(
Elf64_Shdr *sechdrs,
294 unsigned long opdaddr,
299 unsigned int i, num_stubs;
301 num_stubs = sechdrs[me->arch.stubs_section].
sh_size /
sizeof(*stubs);
304 stubs = (
void *)sechdrs[me->arch.stubs_section].
sh_addr;
305 for (i = 0; stubs[
i].
opd.funcaddr; i++) {
309 return (
unsigned long)&stubs[
i];
312 if (!create_stub(sechdrs, &stubs[i], opd, me))
315 return (
unsigned long)&stubs[
i];
323 printk(
"%s: Expect noop after relocate, got %08x\n",
324 me->
name, *instruction);
327 *instruction = 0xe8410028;
333 unsigned int symindex,
338 Elf64_Rela *rela = (
void *)sechdrs[relsec].sh_addr;
343 DEBUGP(
"Applying ADD relocate section %u to %u\n", relsec,
344 sechdrs[relsec].sh_info);
345 for (i = 0; i < sechdrs[relsec].
sh_size /
sizeof(*rela); i++) {
347 location = (
void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
350 sym = (
Elf64_Sym *)sechdrs[symindex].sh_addr
353 DEBUGP(
"RELOC at %p: %li-type as %s (%lu) + %li\n",
364 *(
u32 *)location = value;
369 *(
unsigned long *)location = value;
373 *(
unsigned long *)location = my_r2(sechdrs, me);
378 value -= my_r2(sechdrs, me);
379 if (value + 0x8000 > 0xffff) {
380 printk(
"%s: bad TOC16 relocation (%lu)\n",
385 = (*((
uint16_t *) location) & ~0xffff)
391 value -= my_r2(sechdrs, me);
392 if ((value & 3) != 0 || value + 0x8000 > 0xffff) {
393 printk(
"%s: bad TOC16_DS relocation (%lu)\n",
398 = (*((
uint16_t *) location) & ~0xfffc)
406 value = stub_for_addr(sechdrs, value, me);
409 if (!restore_r2((
u32 *)location + 1, me))
414 value -= (
unsigned long)location;
415 if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){
416 printk(
"%s: REL24 %li out of range!\n",
417 me->
name, (
long int)value);
423 = (*(
uint32_t *)location & ~0x03fffffc)
424 | (value & 0x03fffffc);
429 *location = value - (
unsigned long)location;
433 printk(
"%s: Unknown ADD relocation: %lu\n",
440 #ifdef CONFIG_DYNAMIC_FTRACE
441 me->arch.toc = my_r2(sechdrs, me);
442 me->arch.tramp = stub_for_addr(sechdrs,
443 (
unsigned long)ftrace_caller,