Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 *  This program is free software; you can redistribute it and/or modify
  3 *  it under the terms of the GNU General Public License as published by
  4 *  the Free Software Foundation; either version 2 of the License, or
  5 *  (at your option) any later version.
  6 *
  7 *  This program is distributed in the hope that it will be useful,
  8 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  9 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 10 *  GNU General Public License for more details.
 11 *
 12 *  You should have received a copy of the GNU General Public License
 13 *  along with this program; if not, write to the Free Software
 14 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 15 *
 16 *  Copyright (C) 2001 Rusty Russell.
 17 *  Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
 18 *  Copyright (C) 2005 Thiemo Seufer
 19 */
 20
 21#include <linux/elf.h>
 22#include <linux/err.h>
 23#include <linux/errno.h>
 24#include <linux/moduleloader.h>
 25
 26extern int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v);
 27
 28static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v)
 29{
 30	*location = v;
 31
 32	return 0;
 33}
 34
 35static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
 36{
 37	if (v % 4) {
 38		pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n",
 39		       me->name);
 40		return -ENOEXEC;
 41	}
 42
 43	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
 44		printk(KERN_ERR
 45		       "module %s: relocation overflow\n",
 46		       me->name);
 47		return -ENOEXEC;
 48	}
 49
 50	*location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
 51
 52	return 0;
 53}
 54
 55static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
 56{
 57	*location = (*location & 0xffff0000) |
 58		    ((((long long) v + 0x8000LL) >> 16) & 0xffff);
 59
 60	return 0;
 61}
 62
 63static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v)
 64{
 65	*location = (*location & 0xffff0000) | (v & 0xffff);
 66
 67	return 0;
 68}
 69
 70static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v)
 71{
 72	*(Elf_Addr *)location = v;
 73
 74	return 0;
 75}
 76
 77static int apply_r_mips_higher_rela(struct module *me, u32 *location,
 78				    Elf_Addr v)
 79{
 80	*location = (*location & 0xffff0000) |
 81		    ((((long long) v + 0x80008000LL) >> 32) & 0xffff);
 82
 83	return 0;
 84}
 85
 86static int apply_r_mips_highest_rela(struct module *me, u32 *location,
 87				     Elf_Addr v)
 88{
 89	*location = (*location & 0xffff0000) |
 90		    ((((long long) v + 0x800080008000LL) >> 48) & 0xffff);
 91
 92	return 0;
 93}
 94
 95static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
 96				Elf_Addr v) = {
 97	[R_MIPS_NONE]		= apply_r_mips_none,
 98	[R_MIPS_32]		= apply_r_mips_32_rela,
 99	[R_MIPS_26]		= apply_r_mips_26_rela,
100	[R_MIPS_HI16]		= apply_r_mips_hi16_rela,
101	[R_MIPS_LO16]		= apply_r_mips_lo16_rela,
102	[R_MIPS_64]		= apply_r_mips_64_rela,
103	[R_MIPS_HIGHER]		= apply_r_mips_higher_rela,
104	[R_MIPS_HIGHEST]	= apply_r_mips_highest_rela
105};
106
107int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
108		       unsigned int symindex, unsigned int relsec,
109		       struct module *me)
110{
111	Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
112	int (*handler)(struct module *me, u32 *location, Elf_Addr v);
113	Elf_Sym *sym;
114	u32 *location;
115	unsigned int i, type;
116	Elf_Addr v;
117	int res;
118
119	pr_debug("Applying relocate section %u to %u\n", relsec,
120	       sechdrs[relsec].sh_info);
121
122	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
123		/* This is where to make the change */
124		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
125			+ rel[i].r_offset;
126		/* This is the symbol it is referring to */
127		sym = (Elf_Sym *)sechdrs[symindex].sh_addr
128			+ ELF_MIPS_R_SYM(rel[i]);
129		if (IS_ERR_VALUE(sym->st_value)) {
130			/* Ignore unresolved weak symbol */
131			if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
132				continue;
133			printk(KERN_WARNING "%s: Unknown symbol %s\n",
134			       me->name, strtab + sym->st_name);
135			return -ENOENT;
136		}
137
138		type = ELF_MIPS_R_TYPE(rel[i]);
139
140		if (type < ARRAY_SIZE(reloc_handlers_rela))
141			handler = reloc_handlers_rela[type];
142		else
143			handler = NULL;
144
145		if (!handler) {
146			pr_err("%s: Unknown relocation type %u\n",
147			       me->name, type);
148			return -EINVAL;
149		}
150
151		v = sym->st_value + rel[i].r_addend;
152		res = handler(me, location, v);
153		if (res)
154			return res;
155	}
156
157	return 0;
158}