2 * arch/s390/kernel/module.c - Kernel module help for s390.
5 * Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH,
7 * Author(s): Arnd Bergmann (arndb@de.ibm.com)
8 * Martin Schwidefsky (schwidefsky@de.ibm.com)
10 * based on i386 version
11 * Copyright (C) 2001 Rusty Russell.
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <linux/module.h>
28 #include <linux/elf.h>
29 #include <linux/vmalloc.h>
31 #include <linux/string.h>
32 #include <linux/kernel.h>
33 #include <linux/moduleloader.h>
34 #include <linux/bug.h>
39 #define DEBUGP(fmt , ...)
43 #define PLT_ENTRY_SIZE 12
44 #else /* CONFIG_64BIT */
45 #define PLT_ENTRY_SIZE 20
46 #endif /* CONFIG_64BIT */
48 /* Free memory returned from module_alloc */
49 void module_free(struct module
*mod
, void *module_region
)
52 vfree(mod
->arch
.syminfo
);
53 mod
->arch
.syminfo
= NULL
;
59 check_rela(Elf_Rela
*rela
, struct module
*me
)
61 struct mod_arch_syminfo
*info
;
63 info
= me
->arch
.syminfo
+ ELF_R_SYM (rela
->r_info
);
64 switch (ELF_R_TYPE (rela
->r_info
)) {
65 case R_390_GOT12
: /* 12 bit GOT offset. */
66 case R_390_GOT16
: /* 16 bit GOT offset. */
67 case R_390_GOT20
: /* 20 bit GOT offset. */
68 case R_390_GOT32
: /* 32 bit GOT offset. */
69 case R_390_GOT64
: /* 64 bit GOT offset. */
70 case R_390_GOTENT
: /* 32 bit PC rel. to GOT entry shifted by 1. */
71 case R_390_GOTPLT12
: /* 12 bit offset to jump slot. */
72 case R_390_GOTPLT16
: /* 16 bit offset to jump slot. */
73 case R_390_GOTPLT20
: /* 20 bit offset to jump slot. */
74 case R_390_GOTPLT32
: /* 32 bit offset to jump slot. */
75 case R_390_GOTPLT64
: /* 64 bit offset to jump slot. */
76 case R_390_GOTPLTENT
: /* 32 bit rel. offset to jump slot >> 1. */
77 if (info
->got_offset
== -1UL) {
78 info
->got_offset
= me
->arch
.got_size
;
79 me
->arch
.got_size
+= sizeof(void*);
82 case R_390_PLT16DBL
: /* 16 bit PC rel. PLT shifted by 1. */
83 case R_390_PLT32DBL
: /* 32 bit PC rel. PLT shifted by 1. */
84 case R_390_PLT32
: /* 32 bit PC relative PLT address. */
85 case R_390_PLT64
: /* 64 bit PC relative PLT address. */
86 case R_390_PLTOFF16
: /* 16 bit offset from GOT to PLT. */
87 case R_390_PLTOFF32
: /* 32 bit offset from GOT to PLT. */
88 case R_390_PLTOFF64
: /* 16 bit offset from GOT to PLT. */
89 if (info
->plt_offset
== -1UL) {
90 info
->plt_offset
= me
->arch
.plt_size
;
91 me
->arch
.plt_size
+= PLT_ENTRY_SIZE
;
98 /* Only needed if we want to support loading of
99 modules linked with -shared. */
105 * Account for GOT and PLT relocations. We can't add sections for
106 * got and plt but we can increase the core module size.
109 module_frob_arch_sections(Elf_Ehdr
*hdr
, Elf_Shdr
*sechdrs
,
110 char *secstrings
, struct module
*me
)
118 /* Find symbol table and string table. */
120 for (i
= 0; i
< hdr
->e_shnum
; i
++)
121 switch (sechdrs
[i
].sh_type
) {
123 symtab
= sechdrs
+ i
;
127 printk(KERN_ERR
"module %s: no symbol table\n", me
->name
);
131 /* Allocate one syminfo structure per symbol. */
132 me
->arch
.nsyms
= symtab
->sh_size
/ sizeof(Elf_Sym
);
133 me
->arch
.syminfo
= vmalloc(me
->arch
.nsyms
*
134 sizeof(struct mod_arch_syminfo
));
135 if (!me
->arch
.syminfo
)
137 symbols
= (void *) hdr
+ symtab
->sh_offset
;
138 strings
= (void *) hdr
+ sechdrs
[symtab
->sh_link
].sh_offset
;
139 for (i
= 0; i
< me
->arch
.nsyms
; i
++) {
140 if (symbols
[i
].st_shndx
== SHN_UNDEF
&&
141 strcmp(strings
+ symbols
[i
].st_name
,
142 "_GLOBAL_OFFSET_TABLE_") == 0)
143 /* "Define" it as absolute. */
144 symbols
[i
].st_shndx
= SHN_ABS
;
145 me
->arch
.syminfo
[i
].got_offset
= -1UL;
146 me
->arch
.syminfo
[i
].plt_offset
= -1UL;
147 me
->arch
.syminfo
[i
].got_initialized
= 0;
148 me
->arch
.syminfo
[i
].plt_initialized
= 0;
151 /* Search for got/plt relocations. */
152 me
->arch
.got_size
= me
->arch
.plt_size
= 0;
153 for (i
= 0; i
< hdr
->e_shnum
; i
++) {
154 if (sechdrs
[i
].sh_type
!= SHT_RELA
)
156 nrela
= sechdrs
[i
].sh_size
/ sizeof(Elf_Rela
);
157 rela
= (void *) hdr
+ sechdrs
[i
].sh_offset
;
158 for (j
= 0; j
< nrela
; j
++)
159 check_rela(rela
+ j
, me
);
162 /* Increase core size by size of got & plt and set start
163 offsets for got and plt. */
164 me
->core_size
= ALIGN(me
->core_size
, 4);
165 me
->arch
.got_offset
= me
->core_size
;
166 me
->core_size
+= me
->arch
.got_size
;
167 me
->arch
.plt_offset
= me
->core_size
;
168 me
->core_size
+= me
->arch
.plt_size
;
173 apply_rela(Elf_Rela
*rela
, Elf_Addr base
, Elf_Sym
*symtab
,
176 struct mod_arch_syminfo
*info
;
180 /* This is where to make the change */
181 loc
= base
+ rela
->r_offset
;
182 /* This is the symbol it is referring to. Note that all
183 undefined symbols have been resolved. */
184 r_sym
= ELF_R_SYM(rela
->r_info
);
185 r_type
= ELF_R_TYPE(rela
->r_info
);
186 info
= me
->arch
.syminfo
+ r_sym
;
187 val
= symtab
[r_sym
].st_value
;
190 case R_390_8
: /* Direct 8 bit. */
191 case R_390_12
: /* Direct 12 bit. */
192 case R_390_16
: /* Direct 16 bit. */
193 case R_390_20
: /* Direct 20 bit. */
194 case R_390_32
: /* Direct 32 bit. */
195 case R_390_64
: /* Direct 64 bit. */
196 val
+= rela
->r_addend
;
197 if (r_type
== R_390_8
)
198 *(unsigned char *) loc
= val
;
199 else if (r_type
== R_390_12
)
200 *(unsigned short *) loc
= (val
& 0xfff) |
201 (*(unsigned short *) loc
& 0xf000);
202 else if (r_type
== R_390_16
)
203 *(unsigned short *) loc
= val
;
204 else if (r_type
== R_390_20
)
205 *(unsigned int *) loc
=
206 (*(unsigned int *) loc
& 0xf00000ff) |
207 (val
& 0xfff) << 16 | (val
& 0xff000) >> 4;
208 else if (r_type
== R_390_32
)
209 *(unsigned int *) loc
= val
;
210 else if (r_type
== R_390_64
)
211 *(unsigned long *) loc
= val
;
213 case R_390_PC16
: /* PC relative 16 bit. */
214 case R_390_PC16DBL
: /* PC relative 16 bit shifted by 1. */
215 case R_390_PC32DBL
: /* PC relative 32 bit shifted by 1. */
216 case R_390_PC32
: /* PC relative 32 bit. */
217 case R_390_PC64
: /* PC relative 64 bit. */
218 val
+= rela
->r_addend
- loc
;
219 if (r_type
== R_390_PC16
)
220 *(unsigned short *) loc
= val
;
221 else if (r_type
== R_390_PC16DBL
)
222 *(unsigned short *) loc
= val
>> 1;
223 else if (r_type
== R_390_PC32DBL
)
224 *(unsigned int *) loc
= val
>> 1;
225 else if (r_type
== R_390_PC32
)
226 *(unsigned int *) loc
= val
;
227 else if (r_type
== R_390_PC64
)
228 *(unsigned long *) loc
= val
;
230 case R_390_GOT12
: /* 12 bit GOT offset. */
231 case R_390_GOT16
: /* 16 bit GOT offset. */
232 case R_390_GOT20
: /* 20 bit GOT offset. */
233 case R_390_GOT32
: /* 32 bit GOT offset. */
234 case R_390_GOT64
: /* 64 bit GOT offset. */
235 case R_390_GOTENT
: /* 32 bit PC rel. to GOT entry shifted by 1. */
236 case R_390_GOTPLT12
: /* 12 bit offset to jump slot. */
237 case R_390_GOTPLT20
: /* 20 bit offset to jump slot. */
238 case R_390_GOTPLT16
: /* 16 bit offset to jump slot. */
239 case R_390_GOTPLT32
: /* 32 bit offset to jump slot. */
240 case R_390_GOTPLT64
: /* 64 bit offset to jump slot. */
241 case R_390_GOTPLTENT
: /* 32 bit rel. offset to jump slot >> 1. */
242 if (info
->got_initialized
== 0) {
245 gotent
= me
->module_core
+ me
->arch
.got_offset
+
248 info
->got_initialized
= 1;
250 val
= info
->got_offset
+ rela
->r_addend
;
251 if (r_type
== R_390_GOT12
||
252 r_type
== R_390_GOTPLT12
)
253 *(unsigned short *) loc
= (val
& 0xfff) |
254 (*(unsigned short *) loc
& 0xf000);
255 else if (r_type
== R_390_GOT16
||
256 r_type
== R_390_GOTPLT16
)
257 *(unsigned short *) loc
= val
;
258 else if (r_type
== R_390_GOT20
||
259 r_type
== R_390_GOTPLT20
)
260 *(unsigned int *) loc
=
261 (*(unsigned int *) loc
& 0xf00000ff) |
262 (val
& 0xfff) << 16 | (val
& 0xff000) >> 4;
263 else if (r_type
== R_390_GOT32
||
264 r_type
== R_390_GOTPLT32
)
265 *(unsigned int *) loc
= val
;
266 else if (r_type
== R_390_GOTENT
||
267 r_type
== R_390_GOTPLTENT
)
268 *(unsigned int *) loc
=
269 (val
+ (Elf_Addr
) me
->module_core
- loc
) >> 1;
270 else if (r_type
== R_390_GOT64
||
271 r_type
== R_390_GOTPLT64
)
272 *(unsigned long *) loc
= val
;
274 case R_390_PLT16DBL
: /* 16 bit PC rel. PLT shifted by 1. */
275 case R_390_PLT32DBL
: /* 32 bit PC rel. PLT shifted by 1. */
276 case R_390_PLT32
: /* 32 bit PC relative PLT address. */
277 case R_390_PLT64
: /* 64 bit PC relative PLT address. */
278 case R_390_PLTOFF16
: /* 16 bit offset from GOT to PLT. */
279 case R_390_PLTOFF32
: /* 32 bit offset from GOT to PLT. */
280 case R_390_PLTOFF64
: /* 16 bit offset from GOT to PLT. */
281 if (info
->plt_initialized
== 0) {
283 ip
= me
->module_core
+ me
->arch
.plt_offset
+
286 ip
[0] = 0x0d105810; /* basr 1,0; l 1,6(1); br 1 */
289 #else /* CONFIG_64BIT */
290 ip
[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
293 ip
[3] = (unsigned int) (val
>> 32);
294 ip
[4] = (unsigned int) val
;
295 #endif /* CONFIG_64BIT */
296 info
->plt_initialized
= 1;
298 if (r_type
== R_390_PLTOFF16
||
299 r_type
== R_390_PLTOFF32
||
300 r_type
== R_390_PLTOFF64
)
301 val
= me
->arch
.plt_offset
- me
->arch
.got_offset
+
302 info
->plt_offset
+ rela
->r_addend
;
304 if (!((r_type
== R_390_PLT16DBL
&&
305 val
- loc
+ 0xffffUL
< 0x1ffffeUL
) ||
306 (r_type
== R_390_PLT32DBL
&&
307 val
- loc
+ 0xffffffffULL
< 0x1fffffffeULL
)))
308 val
= (Elf_Addr
) me
->module_core
+
309 me
->arch
.plt_offset
+
311 val
+= rela
->r_addend
- loc
;
313 if (r_type
== R_390_PLT16DBL
)
314 *(unsigned short *) loc
= val
>> 1;
315 else if (r_type
== R_390_PLTOFF16
)
316 *(unsigned short *) loc
= val
;
317 else if (r_type
== R_390_PLT32DBL
)
318 *(unsigned int *) loc
= val
>> 1;
319 else if (r_type
== R_390_PLT32
||
320 r_type
== R_390_PLTOFF32
)
321 *(unsigned int *) loc
= val
;
322 else if (r_type
== R_390_PLT64
||
323 r_type
== R_390_PLTOFF64
)
324 *(unsigned long *) loc
= val
;
326 case R_390_GOTOFF16
: /* 16 bit offset to GOT. */
327 case R_390_GOTOFF32
: /* 32 bit offset to GOT. */
328 case R_390_GOTOFF64
: /* 64 bit offset to GOT. */
329 val
= val
+ rela
->r_addend
-
330 ((Elf_Addr
) me
->module_core
+ me
->arch
.got_offset
);
331 if (r_type
== R_390_GOTOFF16
)
332 *(unsigned short *) loc
= val
;
333 else if (r_type
== R_390_GOTOFF32
)
334 *(unsigned int *) loc
= val
;
335 else if (r_type
== R_390_GOTOFF64
)
336 *(unsigned long *) loc
= val
;
338 case R_390_GOTPC
: /* 32 bit PC relative offset to GOT. */
339 case R_390_GOTPCDBL
: /* 32 bit PC rel. off. to GOT shifted by 1. */
340 val
= (Elf_Addr
) me
->module_core
+ me
->arch
.got_offset
+
341 rela
->r_addend
- loc
;
342 if (r_type
== R_390_GOTPC
)
343 *(unsigned int *) loc
= val
;
344 else if (r_type
== R_390_GOTPCDBL
)
345 *(unsigned int *) loc
= val
>> 1;
348 case R_390_GLOB_DAT
: /* Create GOT entry. */
349 case R_390_JMP_SLOT
: /* Create PLT entry. */
350 case R_390_RELATIVE
: /* Adjust by program base. */
351 /* Only needed if we want to support loading of
352 modules linked with -shared. */
355 printk(KERN_ERR
"module %s: Unknown relocation: %u\n",
363 apply_relocate_add(Elf_Shdr
*sechdrs
, const char *strtab
,
364 unsigned int symindex
, unsigned int relsec
,
373 DEBUGP("Applying relocate section %u to %u\n",
374 relsec
, sechdrs
[relsec
].sh_info
);
375 base
= sechdrs
[sechdrs
[relsec
].sh_info
].sh_addr
;
376 symtab
= (Elf_Sym
*) sechdrs
[symindex
].sh_addr
;
377 rela
= (Elf_Rela
*) sechdrs
[relsec
].sh_addr
;
378 n
= sechdrs
[relsec
].sh_size
/ sizeof(Elf_Rela
);
380 for (i
= 0; i
< n
; i
++, rela
++) {
381 rc
= apply_rela(rela
, base
, symtab
, me
);
388 int module_finalize(const Elf_Ehdr
*hdr
,
389 const Elf_Shdr
*sechdrs
,
392 vfree(me
->arch
.syminfo
);
393 me
->arch
.syminfo
= NULL
;