]>
Commit | Line | Data |
---|---|---|
a17ae4c3 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
1da177e4 | 2 | /* |
a53c8fab | 3 | * Kernel module help for s390. |
1da177e4 LT |
4 | * |
5 | * S390 version | |
a53c8fab | 6 | * Copyright IBM Corp. 2002, 2003 |
1da177e4 LT |
7 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) |
8 | * Martin Schwidefsky (schwidefsky@de.ibm.com) | |
9 | * | |
10 | * based on i386 version | |
11 | * Copyright (C) 2001 Rusty Russell. | |
1da177e4 LT |
12 | */ |
13 | #include <linux/module.h> | |
14 | #include <linux/elf.h> | |
15 | #include <linux/vmalloc.h> | |
16 | #include <linux/fs.h> | |
17 | #include <linux/string.h> | |
18 | #include <linux/kernel.h> | |
2b67fc46 | 19 | #include <linux/moduleloader.h> |
c0007f1a | 20 | #include <linux/bug.h> |
686140a1 | 21 | #include <asm/alternative.h> |
f19fbd5e MS |
22 | #include <asm/nospec-branch.h> |
23 | #include <asm/facility.h> | |
1da177e4 LT |
24 | |
25 | #if 0 | |
26 | #define DEBUGP printk | |
27 | #else | |
28 | #define DEBUGP(fmt , ...) | |
29 | #endif | |
30 | ||
1da177e4 | 31 | #define PLT_ENTRY_SIZE 20 |
1da177e4 | 32 | |
c972cc60 HC |
33 | void *module_alloc(unsigned long size) |
34 | { | |
35 | if (PAGE_ALIGN(size) > MODULES_LEN) | |
36 | return NULL; | |
37 | return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, | |
57d7f939 MS |
38 | GFP_KERNEL, PAGE_KERNEL_EXEC, |
39 | 0, NUMA_NO_NODE, | |
c972cc60 HC |
40 | __builtin_return_address(0)); |
41 | } | |
c972cc60 | 42 | |
d453cded | 43 | void module_arch_freeing_init(struct module *mod) |
1da177e4 | 44 | { |
f31e0960 JY |
45 | if (is_livepatch_module(mod) && |
46 | mod->state == MODULE_STATE_LIVE) | |
47 | return; | |
48 | ||
d453cded RR |
49 | vfree(mod->arch.syminfo); |
50 | mod->arch.syminfo = NULL; | |
1da177e4 LT |
51 | } |
52 | ||
083e14c0 | 53 | static void check_rela(Elf_Rela *rela, struct module *me) |
1da177e4 LT |
54 | { |
55 | struct mod_arch_syminfo *info; | |
56 | ||
57 | info = me->arch.syminfo + ELF_R_SYM (rela->r_info); | |
58 | switch (ELF_R_TYPE (rela->r_info)) { | |
59 | case R_390_GOT12: /* 12 bit GOT offset. */ | |
60 | case R_390_GOT16: /* 16 bit GOT offset. */ | |
61 | case R_390_GOT20: /* 20 bit GOT offset. */ | |
62 | case R_390_GOT32: /* 32 bit GOT offset. */ | |
63 | case R_390_GOT64: /* 64 bit GOT offset. */ | |
64 | case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */ | |
65 | case R_390_GOTPLT12: /* 12 bit offset to jump slot. */ | |
66 | case R_390_GOTPLT16: /* 16 bit offset to jump slot. */ | |
67 | case R_390_GOTPLT20: /* 20 bit offset to jump slot. */ | |
68 | case R_390_GOTPLT32: /* 32 bit offset to jump slot. */ | |
69 | case R_390_GOTPLT64: /* 64 bit offset to jump slot. */ | |
70 | case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */ | |
71 | if (info->got_offset == -1UL) { | |
72 | info->got_offset = me->arch.got_size; | |
73 | me->arch.got_size += sizeof(void*); | |
74 | } | |
75 | break; | |
76 | case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */ | |
77 | case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */ | |
78 | case R_390_PLT32: /* 32 bit PC relative PLT address. */ | |
79 | case R_390_PLT64: /* 64 bit PC relative PLT address. */ | |
80 | case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */ | |
81 | case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */ | |
82 | case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */ | |
83 | if (info->plt_offset == -1UL) { | |
84 | info->plt_offset = me->arch.plt_size; | |
85 | me->arch.plt_size += PLT_ENTRY_SIZE; | |
86 | } | |
87 | break; | |
88 | case R_390_COPY: | |
89 | case R_390_GLOB_DAT: | |
90 | case R_390_JMP_SLOT: | |
91 | case R_390_RELATIVE: | |
92 | /* Only needed if we want to support loading of | |
93 | modules linked with -shared. */ | |
94 | break; | |
95 | } | |
96 | } | |
97 | ||
98 | /* | |
99 | * Account for GOT and PLT relocations. We can't add sections for | |
100 | * got and plt but we can increase the core module size. | |
101 | */ | |
083e14c0 MS |
102 | int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, |
103 | char *secstrings, struct module *me) | |
1da177e4 LT |
104 | { |
105 | Elf_Shdr *symtab; | |
106 | Elf_Sym *symbols; | |
107 | Elf_Rela *rela; | |
108 | char *strings; | |
109 | int nrela, i, j; | |
110 | ||
111 | /* Find symbol table and string table. */ | |
d2c993d8 | 112 | symtab = NULL; |
1da177e4 LT |
113 | for (i = 0; i < hdr->e_shnum; i++) |
114 | switch (sechdrs[i].sh_type) { | |
115 | case SHT_SYMTAB: | |
116 | symtab = sechdrs + i; | |
117 | break; | |
118 | } | |
119 | if (!symtab) { | |
120 | printk(KERN_ERR "module %s: no symbol table\n", me->name); | |
121 | return -ENOEXEC; | |
122 | } | |
123 | ||
124 | /* Allocate one syminfo structure per symbol. */ | |
125 | me->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym); | |
42bc47b3 KC |
126 | me->arch.syminfo = vmalloc(array_size(sizeof(struct mod_arch_syminfo), |
127 | me->arch.nsyms)); | |
1da177e4 LT |
128 | if (!me->arch.syminfo) |
129 | return -ENOMEM; | |
130 | symbols = (void *) hdr + symtab->sh_offset; | |
131 | strings = (void *) hdr + sechdrs[symtab->sh_link].sh_offset; | |
132 | for (i = 0; i < me->arch.nsyms; i++) { | |
133 | if (symbols[i].st_shndx == SHN_UNDEF && | |
134 | strcmp(strings + symbols[i].st_name, | |
135 | "_GLOBAL_OFFSET_TABLE_") == 0) | |
136 | /* "Define" it as absolute. */ | |
137 | symbols[i].st_shndx = SHN_ABS; | |
138 | me->arch.syminfo[i].got_offset = -1UL; | |
139 | me->arch.syminfo[i].plt_offset = -1UL; | |
140 | me->arch.syminfo[i].got_initialized = 0; | |
141 | me->arch.syminfo[i].plt_initialized = 0; | |
142 | } | |
143 | ||
144 | /* Search for got/plt relocations. */ | |
145 | me->arch.got_size = me->arch.plt_size = 0; | |
146 | for (i = 0; i < hdr->e_shnum; i++) { | |
147 | if (sechdrs[i].sh_type != SHT_RELA) | |
148 | continue; | |
149 | nrela = sechdrs[i].sh_size / sizeof(Elf_Rela); | |
150 | rela = (void *) hdr + sechdrs[i].sh_offset; | |
151 | for (j = 0; j < nrela; j++) | |
152 | check_rela(rela + j, me); | |
153 | } | |
154 | ||
155 | /* Increase core size by size of got & plt and set start | |
156 | offsets for got and plt. */ | |
7523e4dc RR |
157 | me->core_layout.size = ALIGN(me->core_layout.size, 4); |
158 | me->arch.got_offset = me->core_layout.size; | |
159 | me->core_layout.size += me->arch.got_size; | |
160 | me->arch.plt_offset = me->core_layout.size; | |
f19fbd5e | 161 | if (me->arch.plt_size) { |
6e179d64 | 162 | if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) |
f19fbd5e MS |
163 | me->arch.plt_size += PLT_ENTRY_SIZE; |
164 | me->core_layout.size += me->arch.plt_size; | |
165 | } | |
1da177e4 LT |
166 | return 0; |
167 | } | |
168 | ||
083e14c0 MS |
169 | static int apply_rela_bits(Elf_Addr loc, Elf_Addr val, |
170 | int sign, int bits, int shift) | |
171 | { | |
172 | unsigned long umax; | |
173 | long min, max; | |
174 | ||
175 | if (val & ((1UL << shift) - 1)) | |
176 | return -ENOEXEC; | |
177 | if (sign) { | |
178 | val = (Elf_Addr)(((long) val) >> shift); | |
179 | min = -(1L << (bits - 1)); | |
180 | max = (1L << (bits - 1)) - 1; | |
181 | if ((long) val < min || (long) val > max) | |
182 | return -ENOEXEC; | |
183 | } else { | |
184 | val >>= shift; | |
185 | umax = ((1UL << (bits - 1)) << 1) - 1; | |
186 | if ((unsigned long) val > umax) | |
187 | return -ENOEXEC; | |
188 | } | |
189 | ||
190 | if (bits == 8) | |
191 | *(unsigned char *) loc = val; | |
192 | else if (bits == 12) | |
193 | *(unsigned short *) loc = (val & 0xfff) | | |
194 | (*(unsigned short *) loc & 0xf000); | |
195 | else if (bits == 16) | |
196 | *(unsigned short *) loc = val; | |
197 | else if (bits == 20) | |
198 | *(unsigned int *) loc = (val & 0xfff) << 16 | | |
199 | (val & 0xff000) >> 4 | | |
200 | (*(unsigned int *) loc & 0xf00000ff); | |
201 | else if (bits == 32) | |
202 | *(unsigned int *) loc = val; | |
203 | else if (bits == 64) | |
204 | *(unsigned long *) loc = val; | |
205 | return 0; | |
206 | } | |
207 | ||
208 | static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, | |
209 | const char *strtab, struct module *me) | |
1da177e4 LT |
210 | { |
211 | struct mod_arch_syminfo *info; | |
212 | Elf_Addr loc, val; | |
213 | int r_type, r_sym; | |
72a6b43e | 214 | int rc = -ENOEXEC; |
1da177e4 LT |
215 | |
216 | /* This is where to make the change */ | |
217 | loc = base + rela->r_offset; | |
218 | /* This is the symbol it is referring to. Note that all | |
219 | undefined symbols have been resolved. */ | |
220 | r_sym = ELF_R_SYM(rela->r_info); | |
221 | r_type = ELF_R_TYPE(rela->r_info); | |
222 | info = me->arch.syminfo + r_sym; | |
223 | val = symtab[r_sym].st_value; | |
224 | ||
225 | switch (r_type) { | |
e80cfc31 HB |
226 | case R_390_NONE: /* No relocation. */ |
227 | rc = 0; | |
228 | break; | |
1da177e4 LT |
229 | case R_390_8: /* Direct 8 bit. */ |
230 | case R_390_12: /* Direct 12 bit. */ | |
231 | case R_390_16: /* Direct 16 bit. */ | |
232 | case R_390_20: /* Direct 20 bit. */ | |
233 | case R_390_32: /* Direct 32 bit. */ | |
234 | case R_390_64: /* Direct 64 bit. */ | |
235 | val += rela->r_addend; | |
236 | if (r_type == R_390_8) | |
083e14c0 | 237 | rc = apply_rela_bits(loc, val, 0, 8, 0); |
1da177e4 | 238 | else if (r_type == R_390_12) |
083e14c0 | 239 | rc = apply_rela_bits(loc, val, 0, 12, 0); |
1da177e4 | 240 | else if (r_type == R_390_16) |
083e14c0 | 241 | rc = apply_rela_bits(loc, val, 0, 16, 0); |
1da177e4 | 242 | else if (r_type == R_390_20) |
083e14c0 | 243 | rc = apply_rela_bits(loc, val, 1, 20, 0); |
1da177e4 | 244 | else if (r_type == R_390_32) |
083e14c0 | 245 | rc = apply_rela_bits(loc, val, 0, 32, 0); |
1da177e4 | 246 | else if (r_type == R_390_64) |
083e14c0 | 247 | rc = apply_rela_bits(loc, val, 0, 64, 0); |
1da177e4 LT |
248 | break; |
249 | case R_390_PC16: /* PC relative 16 bit. */ | |
250 | case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ | |
251 | case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */ | |
252 | case R_390_PC32: /* PC relative 32 bit. */ | |
253 | case R_390_PC64: /* PC relative 64 bit. */ | |
254 | val += rela->r_addend - loc; | |
255 | if (r_type == R_390_PC16) | |
083e14c0 | 256 | rc = apply_rela_bits(loc, val, 1, 16, 0); |
1da177e4 | 257 | else if (r_type == R_390_PC16DBL) |
083e14c0 | 258 | rc = apply_rela_bits(loc, val, 1, 16, 1); |
1da177e4 | 259 | else if (r_type == R_390_PC32DBL) |
083e14c0 | 260 | rc = apply_rela_bits(loc, val, 1, 32, 1); |
1da177e4 | 261 | else if (r_type == R_390_PC32) |
083e14c0 | 262 | rc = apply_rela_bits(loc, val, 1, 32, 0); |
1da177e4 | 263 | else if (r_type == R_390_PC64) |
083e14c0 | 264 | rc = apply_rela_bits(loc, val, 1, 64, 0); |
1da177e4 LT |
265 | break; |
266 | case R_390_GOT12: /* 12 bit GOT offset. */ | |
267 | case R_390_GOT16: /* 16 bit GOT offset. */ | |
268 | case R_390_GOT20: /* 20 bit GOT offset. */ | |
269 | case R_390_GOT32: /* 32 bit GOT offset. */ | |
270 | case R_390_GOT64: /* 64 bit GOT offset. */ | |
271 | case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */ | |
272 | case R_390_GOTPLT12: /* 12 bit offset to jump slot. */ | |
273 | case R_390_GOTPLT20: /* 20 bit offset to jump slot. */ | |
274 | case R_390_GOTPLT16: /* 16 bit offset to jump slot. */ | |
275 | case R_390_GOTPLT32: /* 32 bit offset to jump slot. */ | |
276 | case R_390_GOTPLT64: /* 64 bit offset to jump slot. */ | |
277 | case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */ | |
278 | if (info->got_initialized == 0) { | |
279 | Elf_Addr *gotent; | |
280 | ||
7523e4dc | 281 | gotent = me->core_layout.base + me->arch.got_offset + |
1da177e4 LT |
282 | info->got_offset; |
283 | *gotent = val; | |
284 | info->got_initialized = 1; | |
285 | } | |
286 | val = info->got_offset + rela->r_addend; | |
287 | if (r_type == R_390_GOT12 || | |
288 | r_type == R_390_GOTPLT12) | |
083e14c0 | 289 | rc = apply_rela_bits(loc, val, 0, 12, 0); |
1da177e4 LT |
290 | else if (r_type == R_390_GOT16 || |
291 | r_type == R_390_GOTPLT16) | |
083e14c0 | 292 | rc = apply_rela_bits(loc, val, 0, 16, 0); |
1da177e4 LT |
293 | else if (r_type == R_390_GOT20 || |
294 | r_type == R_390_GOTPLT20) | |
083e14c0 | 295 | rc = apply_rela_bits(loc, val, 1, 20, 0); |
1da177e4 LT |
296 | else if (r_type == R_390_GOT32 || |
297 | r_type == R_390_GOTPLT32) | |
083e14c0 | 298 | rc = apply_rela_bits(loc, val, 0, 32, 0); |
1da177e4 LT |
299 | else if (r_type == R_390_GOT64 || |
300 | r_type == R_390_GOTPLT64) | |
083e14c0 MS |
301 | rc = apply_rela_bits(loc, val, 0, 64, 0); |
302 | else if (r_type == R_390_GOTENT || | |
303 | r_type == R_390_GOTPLTENT) { | |
7523e4dc | 304 | val += (Elf_Addr) me->core_layout.base - loc; |
083e14c0 MS |
305 | rc = apply_rela_bits(loc, val, 1, 32, 1); |
306 | } | |
1da177e4 LT |
307 | break; |
308 | case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */ | |
309 | case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */ | |
310 | case R_390_PLT32: /* 32 bit PC relative PLT address. */ | |
311 | case R_390_PLT64: /* 64 bit PC relative PLT address. */ | |
312 | case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */ | |
313 | case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */ | |
314 | case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */ | |
315 | if (info->plt_initialized == 0) { | |
316 | unsigned int *ip; | |
7523e4dc | 317 | ip = me->core_layout.base + me->arch.plt_offset + |
1da177e4 | 318 | info->plt_offset; |
f19fbd5e MS |
319 | ip[0] = 0x0d10e310; /* basr 1,0 */ |
320 | ip[1] = 0x100a0004; /* lg 1,10(1) */ | |
6e179d64 | 321 | if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) { |
f19fbd5e MS |
322 | unsigned int *ij; |
323 | ij = me->core_layout.base + | |
324 | me->arch.plt_offset + | |
325 | me->arch.plt_size - PLT_ENTRY_SIZE; | |
326 | ip[2] = 0xa7f40000 + /* j __jump_r1 */ | |
327 | (unsigned int)(u16) | |
328 | (((unsigned long) ij - 8 - | |
329 | (unsigned long) ip) / 2); | |
330 | } else { | |
331 | ip[2] = 0x07f10000; /* br %r1 */ | |
332 | } | |
1da177e4 LT |
333 | ip[3] = (unsigned int) (val >> 32); |
334 | ip[4] = (unsigned int) val; | |
1da177e4 LT |
335 | info->plt_initialized = 1; |
336 | } | |
337 | if (r_type == R_390_PLTOFF16 || | |
504665a9 MS |
338 | r_type == R_390_PLTOFF32 || |
339 | r_type == R_390_PLTOFF64) | |
1da177e4 LT |
340 | val = me->arch.plt_offset - me->arch.got_offset + |
341 | info->plt_offset + rela->r_addend; | |
504665a9 MS |
342 | else { |
343 | if (!((r_type == R_390_PLT16DBL && | |
344 | val - loc + 0xffffUL < 0x1ffffeUL) || | |
345 | (r_type == R_390_PLT32DBL && | |
346 | val - loc + 0xffffffffULL < 0x1fffffffeULL))) | |
7523e4dc | 347 | val = (Elf_Addr) me->core_layout.base + |
504665a9 MS |
348 | me->arch.plt_offset + |
349 | info->plt_offset; | |
350 | val += rela->r_addend - loc; | |
351 | } | |
1da177e4 | 352 | if (r_type == R_390_PLT16DBL) |
083e14c0 | 353 | rc = apply_rela_bits(loc, val, 1, 16, 1); |
1da177e4 | 354 | else if (r_type == R_390_PLTOFF16) |
083e14c0 | 355 | rc = apply_rela_bits(loc, val, 0, 16, 0); |
1da177e4 | 356 | else if (r_type == R_390_PLT32DBL) |
083e14c0 | 357 | rc = apply_rela_bits(loc, val, 1, 32, 1); |
1da177e4 LT |
358 | else if (r_type == R_390_PLT32 || |
359 | r_type == R_390_PLTOFF32) | |
083e14c0 | 360 | rc = apply_rela_bits(loc, val, 0, 32, 0); |
1da177e4 LT |
361 | else if (r_type == R_390_PLT64 || |
362 | r_type == R_390_PLTOFF64) | |
083e14c0 | 363 | rc = apply_rela_bits(loc, val, 0, 64, 0); |
1da177e4 LT |
364 | break; |
365 | case R_390_GOTOFF16: /* 16 bit offset to GOT. */ | |
366 | case R_390_GOTOFF32: /* 32 bit offset to GOT. */ | |
367 | case R_390_GOTOFF64: /* 64 bit offset to GOT. */ | |
368 | val = val + rela->r_addend - | |
7523e4dc | 369 | ((Elf_Addr) me->core_layout.base + me->arch.got_offset); |
1da177e4 | 370 | if (r_type == R_390_GOTOFF16) |
083e14c0 | 371 | rc = apply_rela_bits(loc, val, 0, 16, 0); |
1da177e4 | 372 | else if (r_type == R_390_GOTOFF32) |
083e14c0 | 373 | rc = apply_rela_bits(loc, val, 0, 32, 0); |
1da177e4 | 374 | else if (r_type == R_390_GOTOFF64) |
083e14c0 | 375 | rc = apply_rela_bits(loc, val, 0, 64, 0); |
1da177e4 LT |
376 | break; |
377 | case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ | |
378 | case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ | |
7523e4dc | 379 | val = (Elf_Addr) me->core_layout.base + me->arch.got_offset + |
1da177e4 LT |
380 | rela->r_addend - loc; |
381 | if (r_type == R_390_GOTPC) | |
083e14c0 | 382 | rc = apply_rela_bits(loc, val, 1, 32, 0); |
1da177e4 | 383 | else if (r_type == R_390_GOTPCDBL) |
083e14c0 | 384 | rc = apply_rela_bits(loc, val, 1, 32, 1); |
1da177e4 LT |
385 | break; |
386 | case R_390_COPY: | |
387 | case R_390_GLOB_DAT: /* Create GOT entry. */ | |
388 | case R_390_JMP_SLOT: /* Create PLT entry. */ | |
389 | case R_390_RELATIVE: /* Adjust by program base. */ | |
390 | /* Only needed if we want to support loading of | |
391 | modules linked with -shared. */ | |
083e14c0 | 392 | return -ENOEXEC; |
1da177e4 | 393 | default: |
083e14c0 | 394 | printk(KERN_ERR "module %s: unknown relocation: %u\n", |
1da177e4 LT |
395 | me->name, r_type); |
396 | return -ENOEXEC; | |
397 | } | |
083e14c0 MS |
398 | if (rc) { |
399 | printk(KERN_ERR "module %s: relocation error for symbol %s " | |
400 | "(r_type %i, value 0x%lx)\n", | |
401 | me->name, strtab + symtab[r_sym].st_name, | |
402 | r_type, (unsigned long) val); | |
403 | return rc; | |
404 | } | |
1da177e4 LT |
405 | return 0; |
406 | } | |
407 | ||
083e14c0 MS |
408 | int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, |
409 | unsigned int symindex, unsigned int relsec, | |
410 | struct module *me) | |
1da177e4 LT |
411 | { |
412 | Elf_Addr base; | |
413 | Elf_Sym *symtab; | |
414 | Elf_Rela *rela; | |
415 | unsigned long i, n; | |
416 | int rc; | |
417 | ||
418 | DEBUGP("Applying relocate section %u to %u\n", | |
419 | relsec, sechdrs[relsec].sh_info); | |
420 | base = sechdrs[sechdrs[relsec].sh_info].sh_addr; | |
421 | symtab = (Elf_Sym *) sechdrs[symindex].sh_addr; | |
422 | rela = (Elf_Rela *) sechdrs[relsec].sh_addr; | |
423 | n = sechdrs[relsec].sh_size / sizeof(Elf_Rela); | |
424 | ||
425 | for (i = 0; i < n; i++, rela++) { | |
083e14c0 | 426 | rc = apply_rela(rela, base, symtab, strtab, me); |
1da177e4 LT |
427 | if (rc) |
428 | return rc; | |
429 | } | |
430 | return 0; | |
431 | } | |
432 | ||
433 | int module_finalize(const Elf_Ehdr *hdr, | |
434 | const Elf_Shdr *sechdrs, | |
435 | struct module *me) | |
436 | { | |
686140a1 | 437 | const Elf_Shdr *s; |
f19fbd5e MS |
438 | char *secstrings, *secname; |
439 | void *aseg; | |
440 | ||
441 | if (IS_ENABLED(CONFIG_EXPOLINE) && | |
6e179d64 | 442 | !nospec_disable && me->arch.plt_size) { |
f19fbd5e MS |
443 | unsigned int *ij; |
444 | ||
445 | ij = me->core_layout.base + me->arch.plt_offset + | |
446 | me->arch.plt_size - PLT_ENTRY_SIZE; | |
447 | if (test_facility(35)) { | |
448 | ij[0] = 0xc6000000; /* exrl %r0,.+10 */ | |
449 | ij[1] = 0x0005a7f4; /* j . */ | |
450 | ij[2] = 0x000007f1; /* br %r1 */ | |
451 | } else { | |
452 | ij[0] = 0x44000000 | (unsigned int) | |
453 | offsetof(struct lowcore, br_r1_trampoline); | |
454 | ij[1] = 0xa7f40000; /* j . */ | |
455 | } | |
456 | } | |
686140a1 | 457 | |
049a2c2d HC |
458 | secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
459 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { | |
f19fbd5e MS |
460 | aseg = (void *) s->sh_addr; |
461 | secname = secstrings + s->sh_name; | |
686140a1 | 462 | |
f19fbd5e MS |
463 | if (!strcmp(".altinstructions", secname)) |
464 | /* patch .altinstructions */ | |
049a2c2d | 465 | apply_alternatives(aseg, aseg + s->sh_size); |
f19fbd5e MS |
466 | |
467 | if (IS_ENABLED(CONFIG_EXPOLINE) && | |
6cf09958 | 468 | (!strncmp(".s390_indirect", secname, 14))) |
6e179d64 | 469 | nospec_revert(aseg, aseg + s->sh_size); |
f19fbd5e MS |
470 | |
471 | if (IS_ENABLED(CONFIG_EXPOLINE) && | |
6cf09958 | 472 | (!strncmp(".s390_return", secname, 12))) |
6e179d64 | 473 | nospec_revert(aseg, aseg + s->sh_size); |
686140a1 VG |
474 | } |
475 | ||
6f367769 | 476 | jump_label_apply_nops(me); |
5336377d | 477 | return 0; |
1da177e4 | 478 | } |