xref: /linux/arch/arc/kernel/module.c (revision fa1c3ff935179453801d763940c38c3ac2d581eb)
1*fa1c3ff9SVineet Gupta /*
2*fa1c3ff9SVineet Gupta  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
3*fa1c3ff9SVineet Gupta  *
4*fa1c3ff9SVineet Gupta  * This program is free software; you can redistribute it and/or modify
5*fa1c3ff9SVineet Gupta  * it under the terms of the GNU General Public License version 2 as
6*fa1c3ff9SVineet Gupta  * published by the Free Software Foundation.
7*fa1c3ff9SVineet Gupta  */
8*fa1c3ff9SVineet Gupta 
9*fa1c3ff9SVineet Gupta #include <linux/module.h>
10*fa1c3ff9SVineet Gupta #include <linux/moduleloader.h>
11*fa1c3ff9SVineet Gupta #include <linux/kernel.h>
12*fa1c3ff9SVineet Gupta #include <linux/elf.h>
13*fa1c3ff9SVineet Gupta #include <linux/vmalloc.h>
14*fa1c3ff9SVineet Gupta #include <linux/slab.h>
15*fa1c3ff9SVineet Gupta #include <linux/fs.h>
16*fa1c3ff9SVineet Gupta #include <linux/string.h>
17*fa1c3ff9SVineet Gupta 
18*fa1c3ff9SVineet Gupta static inline void arc_write_me(unsigned short *addr, unsigned long value)
19*fa1c3ff9SVineet Gupta {
20*fa1c3ff9SVineet Gupta 	*addr = (value & 0xffff0000) >> 16;
21*fa1c3ff9SVineet Gupta 	*(addr + 1) = (value & 0xffff);
22*fa1c3ff9SVineet Gupta }
23*fa1c3ff9SVineet Gupta 
24*fa1c3ff9SVineet Gupta int apply_relocate_add(Elf32_Shdr *sechdrs,
25*fa1c3ff9SVineet Gupta 		       const char *strtab,
26*fa1c3ff9SVineet Gupta 		       unsigned int symindex,	/* sec index for sym tbl */
27*fa1c3ff9SVineet Gupta 		       unsigned int relsec,	/* sec index for relo sec */
28*fa1c3ff9SVineet Gupta 		       struct module *module)
29*fa1c3ff9SVineet Gupta {
30*fa1c3ff9SVineet Gupta 	int i, n;
31*fa1c3ff9SVineet Gupta 	Elf32_Rela *rel_entry = (void *)sechdrs[relsec].sh_addr;
32*fa1c3ff9SVineet Gupta 	Elf32_Sym *sym_entry, *sym_sec;
33*fa1c3ff9SVineet Gupta 	Elf32_Addr relocation;
34*fa1c3ff9SVineet Gupta 	Elf32_Addr location;
35*fa1c3ff9SVineet Gupta 	Elf32_Addr sec_to_patch;
36*fa1c3ff9SVineet Gupta 	int relo_type;
37*fa1c3ff9SVineet Gupta 
38*fa1c3ff9SVineet Gupta 	sec_to_patch = sechdrs[sechdrs[relsec].sh_info].sh_addr;
39*fa1c3ff9SVineet Gupta 	sym_sec = (Elf32_Sym *) sechdrs[symindex].sh_addr;
40*fa1c3ff9SVineet Gupta 	n = sechdrs[relsec].sh_size / sizeof(*rel_entry);
41*fa1c3ff9SVineet Gupta 
42*fa1c3ff9SVineet Gupta 	pr_debug("\n========== Module Sym reloc ===========================\n");
43*fa1c3ff9SVineet Gupta 	pr_debug("Section to fixup %x\n", sec_to_patch);
44*fa1c3ff9SVineet Gupta 	pr_debug("=========================================================\n");
45*fa1c3ff9SVineet Gupta 	pr_debug("rela->r_off | rela->addend | sym->st_value | ADDR | VALUE\n");
46*fa1c3ff9SVineet Gupta 	pr_debug("=========================================================\n");
47*fa1c3ff9SVineet Gupta 
48*fa1c3ff9SVineet Gupta 	/* Loop thru entries in relocation section */
49*fa1c3ff9SVineet Gupta 	for (i = 0; i < n; i++) {
50*fa1c3ff9SVineet Gupta 
51*fa1c3ff9SVineet Gupta 		/* This is where to make the change */
52*fa1c3ff9SVineet Gupta 		location = sec_to_patch + rel_entry[i].r_offset;
53*fa1c3ff9SVineet Gupta 
54*fa1c3ff9SVineet Gupta 		/* This is the symbol it is referring to.  Note that all
55*fa1c3ff9SVineet Gupta 		   undefined symbols have been resolved.  */
56*fa1c3ff9SVineet Gupta 		sym_entry = sym_sec + ELF32_R_SYM(rel_entry[i].r_info);
57*fa1c3ff9SVineet Gupta 
58*fa1c3ff9SVineet Gupta 		relocation = sym_entry->st_value + rel_entry[i].r_addend;
59*fa1c3ff9SVineet Gupta 
60*fa1c3ff9SVineet Gupta 		pr_debug("\t%x\t\t%x\t\t%x  %x %x [%s]\n",
61*fa1c3ff9SVineet Gupta 			rel_entry[i].r_offset, rel_entry[i].r_addend,
62*fa1c3ff9SVineet Gupta 			sym_entry->st_value, location, relocation,
63*fa1c3ff9SVineet Gupta 			strtab + sym_entry->st_name);
64*fa1c3ff9SVineet Gupta 
65*fa1c3ff9SVineet Gupta 		/* This assumes modules are built with -mlong-calls
66*fa1c3ff9SVineet Gupta 		 * so any branches/jumps are absolute 32 bit jmps
67*fa1c3ff9SVineet Gupta 		 * global data access again is abs 32 bit.
68*fa1c3ff9SVineet Gupta 		 * Both of these are handled by same relocation type
69*fa1c3ff9SVineet Gupta 		 */
70*fa1c3ff9SVineet Gupta 		relo_type = ELF32_R_TYPE(rel_entry[i].r_info);
71*fa1c3ff9SVineet Gupta 
72*fa1c3ff9SVineet Gupta 		if (likely(R_ARC_32_ME == relo_type))
73*fa1c3ff9SVineet Gupta 			arc_write_me((unsigned short *)location, relocation);
74*fa1c3ff9SVineet Gupta 		else if (R_ARC_32 == relo_type)
75*fa1c3ff9SVineet Gupta 			*((Elf32_Addr *) location) = relocation;
76*fa1c3ff9SVineet Gupta 		else
77*fa1c3ff9SVineet Gupta 			goto relo_err;
78*fa1c3ff9SVineet Gupta 
79*fa1c3ff9SVineet Gupta 	}
80*fa1c3ff9SVineet Gupta 	return 0;
81*fa1c3ff9SVineet Gupta 
82*fa1c3ff9SVineet Gupta relo_err:
83*fa1c3ff9SVineet Gupta 	pr_err("%s: unknown relocation: %u\n",
84*fa1c3ff9SVineet Gupta 		module->name, ELF32_R_TYPE(rel_entry[i].r_info));
85*fa1c3ff9SVineet Gupta 	return -ENOEXEC;
86*fa1c3ff9SVineet Gupta 
87*fa1c3ff9SVineet Gupta }
88