11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*  Kernel module help for i386.
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (C) 2001 Rusty Russell.
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/moduleloader.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/elf.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
245a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUGP printk
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUGP(fmt , ...)
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3208cfeacb6bcb37c5cf1a9bc0c930243634631f09Jesper Nilsson#ifdef CONFIG_ETRAX_KMALLOCED_MODULES
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid *module_alloc(unsigned long size)
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3566574cc05438dd0907029075d7e6ec5ac0036fbcJonas Bonn	return kmalloc(size, GFP_KERNEL);
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Free memory returned from module_alloc */
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid module_free(struct module *mod, void *module_region)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4166574cc05438dd0907029075d7e6ec5ac0036fbcJonas Bonn	kfree(module_region);
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4366574cc05438dd0907029075d7e6ec5ac0036fbcJonas Bonn#endif
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint apply_relocate_add(Elf32_Shdr *sechdrs,
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       const char *strtab,
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unsigned int symindex,
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       unsigned int relsec,
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       struct module *me)
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  	unsigned int i;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
545d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik	DEBUGP ("Applying add relocate section %u to %u\n", relsec,
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sechdrs[relsec].sh_info);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < sechdrs[relsec].sh_size / sizeof (*rela); i++) {
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This is where to make the change */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uint32_t *loc
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			= ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   + rela[i].r_offset);
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This is the symbol it is referring to.  Note that all
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   undefined symbols have been resolved.  */
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		Elf32_Sym *sym
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			= ((Elf32_Sym *)sechdrs[symindex].sh_addr
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   + ELF32_R_SYM (rela[i].r_info));
675d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik		switch (ELF32_R_TYPE(rela[i].r_info)) {
685d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik		case R_CRIS_32:
695d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik			*loc = sym->st_value + rela[i].r_addend;
705d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik			break;
715d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik		case R_CRIS_32_PCREL:
725d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik			*loc = sym->st_value - (unsigned)loc + rela[i].r_addend - 4;
735d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik			 break;
745d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik		default:
755d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
765d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik			       me->name, ELF32_R_TYPE(rela[i].r_info));
775d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik			return -ENOEXEC;
785d01e6ce785884a5db5792cd2e5bb36fa82fe23cMikael Starvik		}
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
83