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.
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.
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
16 * Copyright (C) 2001 Rusty Russell.
17 * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
18 * Copyright (C) 2005 Thiemo Seufer
19 * Copyright (C) 2015 Imagination Technologies Ltd.
22 #include <linux/elf.h>
23 #include <linux/err.h>
24 #include <linux/errno.h>
25 #include <linux/moduleloader.h>
27 extern int apply_r_mips_none(struct module
*me
, u32
*location
, Elf_Addr v
);
29 static int apply_r_mips_32_rela(struct module
*me
, u32
*location
, Elf_Addr v
)
36 static int apply_r_mips_26_rela(struct module
*me
, u32
*location
, Elf_Addr v
)
39 pr_err("module %s: dangerous R_MIPS_26 RELA relocation\n",
44 if ((v
& 0xf0000000) != (((unsigned long)location
+ 4) & 0xf0000000)) {
45 pr_err("module %s: relocation overflow\n", me
->name
);
49 *location
= (*location
& ~0x03ffffff) | ((v
>> 2) & 0x03ffffff);
54 static int apply_r_mips_hi16_rela(struct module
*me
, u32
*location
, Elf_Addr v
)
56 *location
= (*location
& 0xffff0000) |
57 ((((long long) v
+ 0x8000LL
) >> 16) & 0xffff);
62 static int apply_r_mips_lo16_rela(struct module
*me
, u32
*location
, Elf_Addr v
)
64 *location
= (*location
& 0xffff0000) | (v
& 0xffff);
69 static int apply_r_mips_pc_rela(struct module
*me
, u32
*location
, Elf_Addr v
,
72 unsigned long mask
= GENMASK(bits
- 1, 0);
73 unsigned long se_bits
;
77 pr_err("module %s: dangerous R_MIPS_PC%u RELA relocation\n",
82 offset
= ((long)v
- (long)location
) >> 2;
84 /* check the sign bit onwards are identical - ie. we didn't overflow */
85 se_bits
= (offset
& BIT(bits
- 1)) ? ~0ul : 0;
86 if ((offset
& ~mask
) != (se_bits
& ~mask
)) {
87 pr_err("module %s: relocation overflow\n", me
->name
);
91 *location
= (*location
& ~mask
) | (offset
& mask
);
96 static int apply_r_mips_pc16_rela(struct module
*me
, u32
*location
, Elf_Addr v
)
98 return apply_r_mips_pc_rela(me
, location
, v
, 16);
101 static int apply_r_mips_pc21_rela(struct module
*me
, u32
*location
, Elf_Addr v
)
103 return apply_r_mips_pc_rela(me
, location
, v
, 21);
106 static int apply_r_mips_pc26_rela(struct module
*me
, u32
*location
, Elf_Addr v
)
108 return apply_r_mips_pc_rela(me
, location
, v
, 26);
111 static int apply_r_mips_64_rela(struct module
*me
, u32
*location
, Elf_Addr v
)
113 *(Elf_Addr
*)location
= v
;
118 static int apply_r_mips_higher_rela(struct module
*me
, u32
*location
,
121 *location
= (*location
& 0xffff0000) |
122 ((((long long) v
+ 0x80008000LL
) >> 32) & 0xffff);
127 static int apply_r_mips_highest_rela(struct module
*me
, u32
*location
,
130 *location
= (*location
& 0xffff0000) |
131 ((((long long) v
+ 0x800080008000LL
) >> 48) & 0xffff);
136 static int (*reloc_handlers_rela
[]) (struct module
*me
, u32
*location
,
138 [R_MIPS_NONE
] = apply_r_mips_none
,
139 [R_MIPS_32
] = apply_r_mips_32_rela
,
140 [R_MIPS_26
] = apply_r_mips_26_rela
,
141 [R_MIPS_HI16
] = apply_r_mips_hi16_rela
,
142 [R_MIPS_LO16
] = apply_r_mips_lo16_rela
,
143 [R_MIPS_PC16
] = apply_r_mips_pc16_rela
,
144 [R_MIPS_64
] = apply_r_mips_64_rela
,
145 [R_MIPS_HIGHER
] = apply_r_mips_higher_rela
,
146 [R_MIPS_HIGHEST
] = apply_r_mips_highest_rela
,
147 [R_MIPS_PC21_S2
] = apply_r_mips_pc21_rela
,
148 [R_MIPS_PC26_S2
] = apply_r_mips_pc26_rela
,
151 int apply_relocate_add(Elf_Shdr
*sechdrs
, const char *strtab
,
152 unsigned int symindex
, unsigned int relsec
,
155 Elf_Mips_Rela
*rel
= (void *) sechdrs
[relsec
].sh_addr
;
156 int (*handler
)(struct module
*me
, u32
*location
, Elf_Addr v
);
159 unsigned int i
, type
;
163 pr_debug("Applying relocate section %u to %u\n", relsec
,
164 sechdrs
[relsec
].sh_info
);
166 for (i
= 0; i
< sechdrs
[relsec
].sh_size
/ sizeof(*rel
); i
++) {
167 /* This is where to make the change */
168 location
= (void *)sechdrs
[sechdrs
[relsec
].sh_info
].sh_addr
170 /* This is the symbol it is referring to */
171 sym
= (Elf_Sym
*)sechdrs
[symindex
].sh_addr
172 + ELF_MIPS_R_SYM(rel
[i
]);
173 if (sym
->st_value
>= -MAX_ERRNO
) {
174 /* Ignore unresolved weak symbol */
175 if (ELF_ST_BIND(sym
->st_info
) == STB_WEAK
)
177 pr_warn("%s: Unknown symbol %s\n",
178 me
->name
, strtab
+ sym
->st_name
);
182 type
= ELF_MIPS_R_TYPE(rel
[i
]);
184 if (type
< ARRAY_SIZE(reloc_handlers_rela
))
185 handler
= reloc_handlers_rela
[type
];
190 pr_err("%s: Unknown relocation type %u\n",
195 v
= sym
->st_value
+ rel
[i
].r_addend
;
196 res
= handler(me
, location
, v
);