11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*  Kernel module help for PPC64.
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (C) 2001, 2003 Rusty Russell IBM Corporation.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is free software; you can redistribute it and/or modify
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    it under the terms of the GNU General Public License as published by
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the Free Software Foundation; either version 2 of the License, or
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (at your option) any later version.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is distributed in the hope that it will be useful,
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    but WITHOUT ANY WARRANTY; without even the implied warranty of
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    GNU General Public License for more details.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You should have received a copy of the GNU General Public License
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    along with this program; if not, write to the Free Software
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/elf.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleloader.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h>
23f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt#include <linux/ftrace.h>
2473c9ceab40b1269d6195e556773167c078ac8311Jeremy Fitzhardinge#include <linux/bug.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/module.h>
2621c4ff80cba5e24932f3ef79c8482c0491630b2bBenjamin Herrenschmidt#include <asm/firmware.h>
27b7bcda631e87eb3466d0baa9885650ba7d7ed89dMichael Ellerman#include <asm/code-patching.h>
28eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve#include <linux/sort.h>
2921c4ff80cba5e24932f3ef79c8482c0491630b2bBenjamin Herrenschmidt
3021c4ff80cba5e24932f3ef79c8482c0491630b2bBenjamin Herrenschmidt#include "setup.h"
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* FIXME: We don't do .init separately.  To do this, we'd need to have
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   a separate r2 value in the init and core section, and stub between
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   them, too.
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Using a magic allocator which places modules within 32MB solves
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   this, and makes other things simpler.  Anton?
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   --RR.  */
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUGP printk
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUGP(fmt , ...)
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Like PPC32, we need little trampolines to do > 24-bit jumps (into
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   the kernel itself).  But on PPC64, these need to be used for every
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   jump, actually, to reset r2 (TOC+0x8000). */
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ppc64_stub_entry
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 28 byte jump instruction sequence (7 instructions) */
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char jump[28];
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char unused[4];
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Data for the above code */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ppc64_opd_entry opd;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We use a stub to fix up r2 (TOC ptr) and to jump to the (external)
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   function which may be more than 24-bits away.  We could simply
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   patch the new r2 value and function pointer into the stub, but it's
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   significantly shorter to put these values at the end of the stub
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   code, and patch the stub address (32-bits relative to the TOC ptr,
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   r2) into the stub. */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ppc64_stub_entry ppc64_stub =
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ .jump = {
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x3d, 0x82, 0x00, 0x00, /* addis   r12,r2, <high> */
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x39, 0x8c, 0x00, 0x00, /* addi    r12,r12, <low> */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Save current r2 value in magic place on the stack. */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xf8, 0x41, 0x00, 0x28, /* std     r2,40(r1) */
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xe9, 0x6c, 0x00, 0x20, /* ld      r11,32(r12) */
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xe8, 0x4c, 0x00, 0x28, /* ld      r2,40(r12) */
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x7d, 0x69, 0x03, 0xa6, /* mtctr   r11 */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x4e, 0x80, 0x04, 0x20  /* bctr */
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} };
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Count how many different 24-bit relocations (different symbol,
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   different addend) */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int count_relocs(const Elf64_Rela *rela, unsigned int num)
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
79eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	unsigned int i, r_info, r_addend, _count_relocs;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME: Only count external ones --RR */
82eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	_count_relocs = 0;
83eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	r_info = 0;
84eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	r_addend = 0;
85eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	for (i = 0; i < num; i++)
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Only count 24-bit relocs, others don't need stubs */
87eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		if (ELF64_R_TYPE(rela[i].r_info) == R_PPC_REL24 &&
88eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		    (r_info != ELF64_R_SYM(rela[i].r_info) ||
89eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		     r_addend != rela[i].r_addend)) {
90eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			_count_relocs++;
91eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			r_info = ELF64_R_SYM(rela[i].r_info);
92eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			r_addend = rela[i].r_addend;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
94eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
95eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	return _count_relocs;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medvestatic int relacmp(const void *_x, const void *_y)
99eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve{
100eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	const Elf64_Rela *x, *y;
101eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
102eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	y = (Elf64_Rela *)_x;
103eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	x = (Elf64_Rela *)_y;
104eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
105eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	/* Compare the entire r_info (as opposed to ELF64_R_SYM(r_info) only) to
106eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	 * make the comparison cheaper/faster. It won't affect the sorting or
107eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	 * the counting algorithms' performance
108eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	 */
109eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	if (x->r_info < y->r_info)
110eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		return -1;
111eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	else if (x->r_info > y->r_info)
112eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		return 1;
113eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	else if (x->r_addend < y->r_addend)
114eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		return -1;
115eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	else if (x->r_addend > y->r_addend)
116eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		return 1;
117eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	else
118eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		return 0;
119eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve}
120eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
121eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medvestatic void relaswap(void *_x, void *_y, int size)
122eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve{
123eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	uint64_t *x, *y, tmp;
124eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	int i;
125eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
126eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	y = (uint64_t *)_x;
127eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	x = (uint64_t *)_y;
128eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
129eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	for (i = 0; i < sizeof(Elf64_Rela) / sizeof(uint64_t); i++) {
130eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		tmp = x[i];
131eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		x[i] = y[i];
132eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve		y[i] = tmp;
133eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve	}
134eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve}
135eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Get size of potential trampolines required. */
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    const Elf64_Shdr *sechdrs)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* One extra reloc so it's always 0-funcaddr terminated */
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long relocs = 1;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned i;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Every relocated section... */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < hdr->e_shnum; i++) {
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sechdrs[i].sh_type == SHT_RELA) {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DEBUGP("Found relocations in section %u\n", i);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DEBUGP("Ptr: %p.  Number: %lu\n",
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       (void *)sechdrs[i].sh_addr,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       sechdrs[i].sh_size / sizeof(Elf64_Rela));
151eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
152eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			/* Sort the relocation information based on a symbol and
153eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			 * addend key. This is a stable O(n*log n) complexity
154eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			 * alogrithm but it will reduce the complexity of
155eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			 * count_relocs() to linear complexity O(n)
156eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			 */
157eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			sort((void *)sechdrs[i].sh_addr,
158eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			     sechdrs[i].sh_size / sizeof(Elf64_Rela),
159eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			     sizeof(Elf64_Rela), relacmp, relaswap);
160eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			relocs += count_relocs((void *)sechdrs[i].sh_addr,
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       sechdrs[i].sh_size
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       / sizeof(Elf64_Rela));
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
167f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt#ifdef CONFIG_DYNAMIC_FTRACE
168f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt	/* make the trampoline to the ftrace_caller */
169f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt	relocs++;
170f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt#endif
171f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEBUGP("Looks like a total of %lu stubs, max\n", relocs);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return relocs * sizeof(struct ppc64_stub_entry);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dedotify_versions(struct modversion_info *vers,
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unsigned long size)
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct modversion_info *end;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (end = (void *)vers + size; vers < end; vers++)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (vers->name[0] == '.')
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memmove(vers->name, vers->name+1, strlen(vers->name));
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Undefined symbols which refer to .funcname, hack to funcname */
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < numsyms; i++) {
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (syms[i].st_shndx == SHN_UNDEF) {
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			char *name = strtab + syms[i].st_name;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (name[0] == '.')
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memmove(name, name+1, strlen(name));
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint module_frob_arch_sections(Elf64_Ehdr *hdr,
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      Elf64_Shdr *sechdrs,
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      char *secstrings,
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct module *me)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Find .toc and .stubs sections, symtab and strtab */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < hdr->e_shnum; i++) {
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char *p;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strcmp(secstrings + sechdrs[i].sh_name, ".stubs") == 0)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			me->arch.stubs_section = i;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (strcmp(secstrings + sechdrs[i].sh_name, ".toc") == 0)
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			me->arch.toc_section = i;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (strcmp(secstrings+sechdrs[i].sh_name,"__versions")==0)
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dedotify_versions((void *)hdr + sechdrs[i].sh_offset,
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  sechdrs[i].sh_size);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We don't handle .init for the moment: rename to _init */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while ((p = strstr(secstrings + sechdrs[i].sh_name, ".init")))
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p[0] = '_';
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sechdrs[i].sh_type == SHT_SYMTAB)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dedotify((void *)hdr + sechdrs[i].sh_offset,
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 sechdrs[i].sh_size / sizeof(Elf64_Sym),
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 (void *)hdr
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 + sechdrs[sechdrs[i].sh_link].sh_offset);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
228f749edae5ebd339eaf22508572233600f717424fAlan Modra
229f749edae5ebd339eaf22508572233600f717424fAlan Modra	if (!me->arch.stubs_section) {
230f749edae5ebd339eaf22508572233600f717424fAlan Modra		printk("%s: doesn't contain .stubs.\n", me->name);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOEXEC;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
234f749edae5ebd339eaf22508572233600f717424fAlan Modra	/* If we don't have a .toc, just use .stubs.  We need to set r2
235f749edae5ebd339eaf22508572233600f717424fAlan Modra	   to some reasonable value in case the module calls out to
236f749edae5ebd339eaf22508572233600f717424fAlan Modra	   other functions via a stub, or if a function pointer escapes
237f749edae5ebd339eaf22508572233600f717424fAlan Modra	   the module by some means.  */
238f749edae5ebd339eaf22508572233600f717424fAlan Modra	if (!me->arch.toc_section)
239f749edae5ebd339eaf22508572233600f717424fAlan Modra		me->arch.toc_section = me->arch.stubs_section;
240f749edae5ebd339eaf22508572233600f717424fAlan Modra
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Override the stubs size */
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sechdrs[me->arch.stubs_section].sh_size = get_stubs_size(hdr, sechdrs);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   gives the value maximum span in an instruction which uses a signed
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   offset) */
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned long my_r2(Elf64_Shdr *sechdrs, struct module *me)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sechdrs[me->arch.toc_section].sh_addr + 0x8000;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Both low and high 16 bits are added as SIGNED additions, so if low
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   16 bits has high bit set, high 16 bits must be adjusted.  These
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   macros do that (stolen from binutils). */
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PPC_LO(v) ((v) & 0xffff)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PPC_HI(v) (((v) >> 16) & 0xffff)
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PPC_HA(v) PPC_HI ((v) + 0x8000)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Patch stub to reference function and correct r2 value. */
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int create_stub(Elf64_Shdr *sechdrs,
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct ppc64_stub_entry *entry,
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct ppc64_opd_entry *opd,
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct module *me)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Elf64_Half *loc1, *loc2;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long reladdr;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*entry = ppc64_stub;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	loc1 = (Elf64_Half *)&entry->jump[2];
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	loc2 = (Elf64_Half *)&entry->jump[6];
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Stub uses address relative to r2. */
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reladdr = (unsigned long)entry - my_r2(sechdrs, me);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) {
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("%s: Address %p of stub out of range of %p.\n",
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       me->name, (void *)reladdr, (void *)my_r2);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEBUGP("Stub %p get data from reladdr %li\n", entry, reladdr);
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*loc1 = PPC_HA(reladdr);
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*loc2 = PPC_LO(reladdr);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry->opd.funcaddr = opd->funcaddr;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry->opd.r2 = opd->r2;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Create stub to jump to function described in this OPD: we need the
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   stub to set up the TOC ptr (r2) for the function. */
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   unsigned long opdaddr,
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   struct module *me)
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ppc64_stub_entry *stubs;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ppc64_opd_entry *opd = (void *)opdaddr;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i, num_stubs;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	num_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*stubs);
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Find this stub, or if that fails, the next avail. entry */
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stubs = (void *)sechdrs[me->arch.stubs_section].sh_addr;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; stubs[i].opd.funcaddr; i++) {
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_ON(i >= num_stubs);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (stubs[i].opd.funcaddr == opd->funcaddr)
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (unsigned long)&stubs[i];
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!create_stub(sechdrs, &stubs[i], opd, me))
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (unsigned long)&stubs[i];
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We expect a noop next: if it is, replace it with instruction to
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   restore r2. */
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int restore_r2(u32 *instruction, struct module *me)
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32216c57b3620d77e0bc981da5ef32beae730512684Kumar Gala	if (*instruction != PPC_INST_NOP) {
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("%s: Expect noop after relocate, got %08x\n",
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       me->name, *instruction);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*instruction = 0xe8410028;	/* ld r2,40(r1) */
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint apply_relocate_add(Elf64_Shdr *sechdrs,
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       const char *strtab,
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unsigned int symindex,
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unsigned int relsec,
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       struct module *me)
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Elf64_Sym *sym;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *location;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long value;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEBUGP("Applying ADD relocate section %u to %u\n", relsec,
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       sechdrs[relsec].sh_info);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This is where to make the change */
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			+ rela[i].r_offset;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This is the symbol it is referring to */
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			+ ELF64_R_SYM(rela[i].r_info);
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DEBUGP("RELOC at %p: %li-type as %s (%lu) + %li\n",
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       location, (long)ELF64_R_TYPE(rela[i].r_info),
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       strtab + sym->st_name, (unsigned long)sym->st_value,
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (long)rela[i].r_addend);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* `Everything is relative'. */
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		value = sym->st_value + rela[i].r_addend;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (ELF64_R_TYPE(rela[i].r_info)) {
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case R_PPC64_ADDR32:
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Simply set it */
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*(u32 *)location = value;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
366eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case R_PPC64_ADDR64:
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Simply set it */
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*(unsigned long *)location = value;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case R_PPC64_TOC:
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*(unsigned long *)location = my_r2(sechdrs, me);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3769149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner		case R_PPC64_TOC16:
377f749edae5ebd339eaf22508572233600f717424fAlan Modra			/* Subtract TOC pointer */
3789149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner			value -= my_r2(sechdrs, me);
3799149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner			if (value + 0x8000 > 0xffff) {
3809149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner				printk("%s: bad TOC16 relocation (%lu)\n",
3819149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner				       me->name, value);
3829149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner				return -ENOEXEC;
3839149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner			}
3849149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner			*((uint16_t *) location)
3859149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner				= (*((uint16_t *) location) & ~0xffff)
3869149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner				| (value & 0xffff);
3879149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner			break;
3889149ccfa3571eaa4a4b444777d67fc4ed3ebcf27Peter Bergner
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case R_PPC64_TOC16_DS:
390f749edae5ebd339eaf22508572233600f717424fAlan Modra			/* Subtract TOC pointer */
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			value -= my_r2(sechdrs, me);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((value & 3) != 0 || value + 0x8000 > 0xffff) {
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("%s: bad TOC16_DS relocation (%lu)\n",
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       me->name, value);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOEXEC;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*((uint16_t *) location)
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				= (*((uint16_t *) location) & ~0xfffc)
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				| (value & 0xfffc);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case R_PPC_REL24:
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME: Handle weak symbols here --RR */
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (sym->st_shndx == SHN_UNDEF) {
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* External: go via stub */
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = stub_for_addr(sechdrs, value, me);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!value)
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!restore_r2((u32 *)location + 1, me))
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOEXEC;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Convert value to relative */
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			value -= (unsigned long)location;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("%s: REL24 %li out of range!\n",
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       me->name, (long int)value);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOEXEC;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Only replace bits 2 through 26 */
422eda09fbdcd8c5afaa81c2f1d28e8b9725bad4d5aEmil Medve			*(uint32_t *)location
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				= (*(uint32_t *)location & ~0x03fffffc)
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				| (value & 0x03fffffc);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42721c4ff80cba5e24932f3ef79c8482c0491630b2bBenjamin Herrenschmidt		case R_PPC64_REL64:
42821c4ff80cba5e24932f3ef79c8482c0491630b2bBenjamin Herrenschmidt			/* 64 bits relative (used by features fixups) */
42921c4ff80cba5e24932f3ef79c8482c0491630b2bBenjamin Herrenschmidt			*location = value - (unsigned long)location;
43021c4ff80cba5e24932f3ef79c8482c0491630b2bBenjamin Herrenschmidt			break;
43121c4ff80cba5e24932f3ef79c8482c0491630b2bBenjamin Herrenschmidt
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("%s: Unknown ADD relocation: %lu\n",
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       me->name,
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       (unsigned long)ELF64_R_TYPE(rela[i].r_info));
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOEXEC;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
440f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt#ifdef CONFIG_DYNAMIC_FTRACE
441f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt	me->arch.toc = my_r2(sechdrs, me);
442f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt	me->arch.tramp = stub_for_addr(sechdrs,
443f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt				       (unsigned long)ftrace_caller,
444f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt				       me);
445f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt#endif
446f48cb8b48b0b10025ca9c451b9b32cac3fcd33baSteven Rostedt
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
449