]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/elf_machdep.c
Merge missed sources for lldb-specific TableGen tool.
[FreeBSD/FreeBSD.git] / sys / mips / mips / elf_machdep.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright 1996-1998 John D. Polstra.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  *      from: src/sys/i386/i386/elf_machdep.c,v 1.20 2004/08/11 02:35:05 marcel
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
36 #include <sys/exec.h>
37 #include <sys/imgact.h>
38 #include <sys/linker.h>
39 #include <sys/sysent.h>
40 #include <sys/imgact_elf.h>
41 #include <sys/proc.h>
42 #include <sys/syscall.h>
43 #include <sys/signalvar.h>
44 #include <sys/vnode.h>
45
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48 #include <vm/vm_param.h>
49
50 #include <machine/elf.h>
51 #include <machine/md_var.h>
52 #include <machine/cache.h>
53
54 #ifdef __mips_n64
55 struct sysentvec elf64_freebsd_sysvec = {
56         .sv_size        = SYS_MAXSYSCALL,
57         .sv_table       = sysent,
58         .sv_errsize     = 0,
59         .sv_errtbl      = NULL,
60         .sv_transtrap   = NULL,
61         .sv_fixup       = __elfN(freebsd_fixup),
62         .sv_sendsig     = sendsig,
63         .sv_sigcode     = sigcode,
64         .sv_szsigcode   = &szsigcode,
65         .sv_name        = "FreeBSD ELF64",
66         .sv_coredump    = __elfN(coredump),
67         .sv_imgact_try  = NULL,
68         .sv_minsigstksz = MINSIGSTKSZ,
69         .sv_minuser     = VM_MIN_ADDRESS,
70         .sv_maxuser     = VM_MAXUSER_ADDRESS,
71         .sv_usrstack    = USRSTACK,
72         .sv_psstrings   = PS_STRINGS,
73         .sv_stackprot   = VM_PROT_ALL,
74         .sv_copyout_strings = exec_copyout_strings,
75         .sv_setregs     = exec_setregs,
76         .sv_fixlimit    = NULL,
77         .sv_maxssiz     = NULL,
78         .sv_flags       = SV_ABI_FREEBSD | SV_LP64 | SV_ASLR,
79         .sv_set_syscall_retval = cpu_set_syscall_retval,
80         .sv_fetch_syscall_args = cpu_fetch_syscall_args,
81         .sv_syscallnames = syscallnames,
82         .sv_schedtail   = NULL,
83         .sv_thread_detach = NULL,
84         .sv_trap        = NULL,
85 };
86
87 static Elf64_Brandinfo freebsd_brand_info = {
88         .brand          = ELFOSABI_FREEBSD,
89         .machine        = EM_MIPS,
90         .compat_3_brand = "FreeBSD",
91         .emul_path      = NULL,
92         .interp_path    = "/libexec/ld-elf.so.1",
93         .sysvec         = &elf64_freebsd_sysvec,
94         .interp_newpath = NULL,
95         .brand_note     = &elf64_freebsd_brandnote,
96         .flags          = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
97 };
98
99 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
100     (sysinit_cfunc_t) elf64_insert_brand_entry,
101     &freebsd_brand_info);
102
103 void
104 elf64_dump_thread(struct thread *td __unused, void *dst __unused,
105     size_t *off __unused)
106 {
107 }
108 #else
109 struct sysentvec elf32_freebsd_sysvec = {
110         .sv_size        = SYS_MAXSYSCALL,
111         .sv_table       = sysent,
112         .sv_errsize     = 0,
113         .sv_errtbl      = NULL,
114         .sv_transtrap   = NULL,
115         .sv_fixup       = __elfN(freebsd_fixup),
116         .sv_sendsig     = sendsig,
117         .sv_sigcode     = sigcode,
118         .sv_szsigcode   = &szsigcode,
119         .sv_name        = "FreeBSD ELF32",
120         .sv_coredump    = __elfN(coredump),
121         .sv_imgact_try  = NULL,
122         .sv_minsigstksz = MINSIGSTKSZ,
123         .sv_minuser     = VM_MIN_ADDRESS,
124         .sv_maxuser     = VM_MAXUSER_ADDRESS,
125         .sv_usrstack    = USRSTACK,
126         .sv_psstrings   = PS_STRINGS,
127         .sv_stackprot   = VM_PROT_ALL,
128         .sv_copyout_strings = exec_copyout_strings,
129         .sv_setregs     = exec_setregs,
130         .sv_fixlimit    = NULL,
131         .sv_maxssiz     = NULL,
132         .sv_flags       = SV_ABI_FREEBSD | SV_ILP32 | SV_ASLR,
133         .sv_set_syscall_retval = cpu_set_syscall_retval,
134         .sv_fetch_syscall_args = cpu_fetch_syscall_args,
135         .sv_syscallnames = syscallnames,
136         .sv_schedtail   = NULL,
137         .sv_thread_detach = NULL,
138         .sv_trap        = NULL,
139 };
140
141 static Elf32_Brandinfo freebsd_brand_info = {
142         .brand          = ELFOSABI_FREEBSD,
143         .machine        = EM_MIPS,
144         .compat_3_brand = "FreeBSD",
145         .emul_path      = NULL,
146         .interp_path    = "/libexec/ld-elf.so.1",
147         .sysvec         = &elf32_freebsd_sysvec,
148         .interp_newpath = NULL,
149         .brand_note     = &elf32_freebsd_brandnote,
150         .flags          = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
151 };
152
153 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST,
154     (sysinit_cfunc_t) elf32_insert_brand_entry,
155     &freebsd_brand_info);
156
157 void
158 elf32_dump_thread(struct thread *td __unused, void *dst __unused,
159     size_t *off __unused)
160 {
161 }
162 #endif
163
164 /*
165  * The following MIPS relocation code for tracking multiple
166  * consecutive HI32/LO32 entries is because of the following:
167  *
168  * https://dmz-portal.mips.com/wiki/MIPS_relocation_types
169  *
170  * ===
171  *
172  * + R_MIPS_HI16
173  *
174  * An R_MIPS_HI16 must be followed eventually by an associated R_MIPS_LO16
175  * relocation record in the same SHT_REL section. The contents of the two
176  * fields to be relocated are combined to form a full 32-bit addend AHL.
177  * An R_MIPS_LO16 entry which does not immediately follow a R_MIPS_HI16 is
178  * combined with the most recent one encountered, i.e. multiple R_MIPS_LO16
179  * entries may be associated with a single R_MIPS_HI16. Use of these
180  * relocation types in a SHT_REL section is discouraged and may be
181  * forbidden to avoid this complication.
182  *
183  * A GNU extension allows multiple R_MIPS_HI16 records to share the same
184  * R_MIPS_LO16 relocation record(s). The association works like this within
185  * a single relocation section:
186  *
187  * + From the beginning of the section moving to the end of the section,
188  *   until R_MIPS_LO16 is not found each found R_MIPS_HI16 relocation will
189  *   be associated with the first R_MIPS_LO16.
190  *
191  * + Until another R_MIPS_HI16 record is found all found R_MIPS_LO16
192  *   relocations found are associated with the last R_MIPS_HI16.
193  *
194  * ===
195  *
196  * This is so gcc can do dead code detection/removal without having to
197  * generate HI/LO pairs even if one of them would be deleted.
198  *
199  * So, the summary is:
200  *
201  * + A HI16 entry must occur before any LO16 entries;
202  * + Multiple consecutive HI16 RELA entries need to be buffered until the
203  *   first LO16 RELA entry occurs - and then all HI16 RELA relocations use
204  *   the offset in the LOW16 RELA for calculating their offsets;
205  * + The last HI16 RELA entry before a LO16 RELA entry is used (the AHL)
206  *   for the first subsequent LO16 calculation;
207  * + If multiple consecutive LO16 RELA entries occur, only the first
208  *   LO16 RELA entry triggers an update of buffered HI16 RELA entries;
209  *   any subsequent LO16 RELA entry before another HI16 RELA entry will
210  *   not cause any further updates to the HI16 RELA entries.
211  *
212  * Additionally, flush out any outstanding HI16 entries that don't have
213  * a LO16 entry in case some garbage entries are left in the file.
214  */
215
216 struct mips_tmp_reloc;
217 struct mips_tmp_reloc {
218         struct mips_tmp_reloc *next;
219
220         Elf_Addr ahl;
221         Elf32_Addr *where_hi16;
222 };
223
224 static struct mips_tmp_reloc *ml = NULL;
225
226 /*
227  * Add a temporary relocation (ie, a HI16 reloc type.)
228  */
229 static int
230 mips_tmp_reloc_add(Elf_Addr ahl, Elf32_Addr *where_hi16)
231 {
232         struct mips_tmp_reloc *r;
233
234         r = malloc(sizeof(struct mips_tmp_reloc), M_TEMP, M_NOWAIT);
235         if (r == NULL) {
236                 printf("%s: failed to malloc\n", __func__);
237                 return (0);
238         }
239
240         r->ahl = ahl;
241         r->where_hi16 = where_hi16;
242         r->next = ml;
243         ml = r;
244
245         return (1);
246 }
247
248 /*
249  * Flush the temporary relocation list.
250  *
251  * This should be done after a file is completely loaded
252  * so no stale relocations exist to confuse the next
253  * load.
254  */
255 static void
256 mips_tmp_reloc_flush(void)
257 {
258         struct mips_tmp_reloc *r, *rn;
259
260         r = ml;
261         ml = NULL;
262         while (r != NULL) {
263                 rn = r->next;
264                 free(r, M_TEMP);
265                 r = rn;
266         }
267 }
268
269 /*
270  * Get an entry from the reloc list; or NULL if we've run out.
271  */
272 static struct mips_tmp_reloc *
273 mips_tmp_reloc_get(void)
274 {
275         struct mips_tmp_reloc *r;
276
277         r = ml;
278         if (r == NULL)
279                 return (NULL);
280         ml = ml->next;
281         return (r);
282 }
283
284 /*
285  * Free a relocation entry.
286  */
287 static void
288 mips_tmp_reloc_free(struct mips_tmp_reloc *r)
289 {
290
291         free(r, M_TEMP);
292 }
293
294 bool
295 elf_is_ifunc_reloc(Elf_Size r_info __unused)
296 {
297
298         return (false);
299 }
300
301 /* Process one elf relocation with addend. */
302 static int
303 elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
304     int type, int local, elf_lookup_fn lookup)
305 {
306         Elf32_Addr *where = (Elf32_Addr *)NULL;
307         Elf_Addr addr;
308         Elf_Addr addend = (Elf_Addr)0;
309         Elf_Word rtype = (Elf_Word)0, symidx;
310         struct mips_tmp_reloc *r;
311         const Elf_Rel *rel = NULL;
312         const Elf_Rela *rela = NULL;
313         int error;
314
315         /* Store the last seen ahl from a HI16 for LO16 processing */
316         static Elf_Addr last_ahl;
317
318         switch (type) {
319         case ELF_RELOC_REL:
320                 rel = (const Elf_Rel *)data;
321                 where = (Elf32_Addr *) (relocbase + rel->r_offset);
322                 rtype = ELF_R_TYPE(rel->r_info);
323                 symidx = ELF_R_SYM(rel->r_info);
324                 switch (rtype) {
325                 case R_MIPS_64:
326                         addend = *(Elf64_Addr *)where;
327                         break;
328                 default:
329                         addend = *where;
330                         break;
331                 }
332
333                 break;
334         case ELF_RELOC_RELA:
335                 rela = (const Elf_Rela *)data;
336                 where = (Elf32_Addr *) (relocbase + rela->r_offset);
337                 addend = rela->r_addend;
338                 rtype = ELF_R_TYPE(rela->r_info);
339                 symidx = ELF_R_SYM(rela->r_info);
340                 break;
341         default:
342                 panic("unknown reloc type %d\n", type);
343         }
344
345         switch (rtype) {
346         case R_MIPS_NONE:       /* none */
347                 break;
348
349         case R_MIPS_32:         /* S + A */
350                 error = lookup(lf, symidx, 1, &addr);
351                 if (error != 0)
352                         return (-1);
353                 addr += addend;
354                 if (*where != addr)
355                         *where = (Elf32_Addr)addr;
356                 break;
357
358         case R_MIPS_26:         /* ((A << 2) | (P & 0xf0000000) + S) >> 2 */
359                 error = lookup(lf, symidx, 1, &addr);
360                 if (error != 0)
361                         return (-1);
362
363                 addend &= 0x03ffffff;
364                 /*
365                  * Addendum for .rela R_MIPS_26 is not shifted right
366                  */
367                 if (rela == NULL)
368                         addend <<= 2;
369
370                 addr += ((Elf_Addr)where & 0xf0000000) | addend;
371                 addr >>= 2;
372
373                 *where &= ~0x03ffffff;
374                 *where |= addr & 0x03ffffff;
375                 break;
376
377         case R_MIPS_64:         /* S + A */
378                 error = lookup(lf, symidx, 1, &addr);
379                 if (error != 0)
380                         return (-1);
381                 addr += addend;
382                 if (*(Elf64_Addr*)where != addr)
383                         *(Elf64_Addr*)where = addr;
384                 break;
385
386         /*
387          * Handle the two GNU extension cases:
388          *
389          * + Multiple HI16s followed by a LO16, and
390          * + A HI16 followed by multiple LO16s.
391          *
392          * The former is tricky - the HI16 relocations need
393          * to be buffered until a LO16 occurs, at which point
394          * each HI16 is replayed against the LO16 relocation entry
395          * (with the relevant overflow information.)
396          *
397          * The latter should be easy to handle - when the
398          * first LO16 is seen, write out and flush the
399          * HI16 buffer.  Any subsequent LO16 entries will
400          * find a blank relocation buffer.
401          *
402          */
403
404         case R_MIPS_HI16:       /* ((AHL + S) - ((short)(AHL + S)) >> 16 */
405                 if (rela != NULL) {
406                         error = lookup(lf, symidx, 1, &addr);
407                         if (error != 0)
408                                 return (-1);
409                         addr += addend;
410                         *where &= 0xffff0000;
411                         *where |= ((((long long) addr + 0x8000LL) >> 16) & 0xffff);
412                 } else {
413                         /*
414                          * Add a temporary relocation to the list;
415                          * will pop it off / free the list when
416                          * we've found a suitable HI16.
417                          */
418                         if (mips_tmp_reloc_add(addend << 16, where) == 0)
419                                 return (-1);
420                         /*
421                          * Track the last seen HI16 AHL for use by
422                          * the first LO16 AHL calculation.
423                          *
424                          * The assumption is any intermediary deleted
425                          * LO16's were optimised out, so the last
426                          * HI16 before the LO16 is the "true" relocation
427                          * entry to use for that LO16 write.
428                          */
429                         last_ahl = addend << 16;
430                 }
431                 break;
432
433         case R_MIPS_LO16:       /* AHL + S */
434                 if (rela != NULL) {
435                         error = lookup(lf, symidx, 1, &addr);
436                         if (error != 0)
437                                 return (-1);
438                         addr += addend;
439                         *where &= 0xffff0000;
440                         *where |= addr & 0xffff;
441                 } else {
442                         Elf_Addr tmp_ahl;
443                         Elf_Addr tmp_addend;
444
445                         tmp_ahl = last_ahl + (int16_t) addend;
446                         error = lookup(lf, symidx, 1, &addr);
447                         if (error != 0)
448                                 return (-1);
449
450                         tmp_addend = addend & 0xffff0000;
451
452                         /* Use the last seen ahl for calculating addend */
453                         tmp_addend |= (uint16_t)(tmp_ahl + addr);
454                         *where = tmp_addend;
455
456                         /*
457                          * This logic implements the "we saw multiple HI16
458                          * before a LO16" assignment /and/ "we saw multiple
459                          * LO16s".
460                          *
461                          * Multiple LO16s will be handled as a blank
462                          * relocation list.
463                          *
464                          * Multple HI16's are iterated over here.
465                          */
466                         while ((r = mips_tmp_reloc_get()) != NULL) {
467                                 Elf_Addr rahl;
468
469                                 /*
470                                  * We have the ahl from the HI16 entry, so
471                                  * offset it by the 16 bits of the low ahl.
472                                  */
473                                 rahl = r->ahl;
474                                 rahl += (int16_t) addend;
475
476                                 tmp_addend = *(r->where_hi16);
477                                 tmp_addend &= 0xffff0000;
478                                 tmp_addend |= ((rahl + addr) -
479                                     (int16_t)(rahl + addr)) >> 16;
480                                 *(r->where_hi16) = tmp_addend;
481                                 mips_tmp_reloc_free(r);
482                         }
483                 }
484
485                 break;
486
487         case R_MIPS_HIGHER:     /* %higher(A+S) */
488                 error = lookup(lf, symidx, 1, &addr);
489                 if (error != 0)
490                         return (-1);
491                 addr += addend;
492                 *where &= 0xffff0000;
493                 *where |= (((long long)addr + 0x80008000LL) >> 32) & 0xffff;
494                 break;
495
496         case R_MIPS_HIGHEST:    /* %highest(A+S) */
497                 error = lookup(lf, symidx, 1, &addr);
498                 if (error != 0)
499                         return (-1);
500                 addr += addend;
501                 *where &= 0xffff0000;
502                 *where |= (((long long)addr + 0x800080008000LL) >> 48) & 0xffff;
503                 break;
504
505         default:
506                 printf("kldload: unexpected relocation type %d\n",
507                         rtype);
508                 return (-1);
509         }
510
511         return(0);
512 }
513
514 int
515 elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
516     elf_lookup_fn lookup)
517 {
518
519         return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
520 }
521
522 int
523 elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
524     int type, elf_lookup_fn lookup)
525 {
526
527         return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
528 }
529
530 int
531 elf_cpu_load_file(linker_file_t lf __unused)
532 {
533
534         /*
535          * Sync the I and D caches to make sure our relocations are visible.
536          */
537         mips_icache_sync_all();
538
539         /* Flush outstanding relocations */
540         mips_tmp_reloc_flush();
541
542         return (0);
543 }
544
545 int
546 elf_cpu_unload_file(linker_file_t lf __unused)
547 {
548
549         return (0);
550 }