Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / i386 / i386 / elf_machdep.c
1 /*-
2  * Copyright 1996-1998 John D. Polstra.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * $FreeBSD: src/sys/i386/i386/elf_machdep.c,v 1.8 1999/12/21 11:14:02 eivind Exp $
26  */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/linker.h>
31 #include <machine/elf.h>
32
33 /* Process one elf relocation with addend. */
34 int
35 elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
36 {
37         Elf_Addr relocbase = (Elf_Addr) lf->address;
38         Elf_Addr *where;
39         Elf_Addr addr;
40         Elf_Addr addend;
41         Elf_Word rtype;
42         const Elf_Rel *rel;
43         const Elf_Rela *rela;
44
45         switch (type) {
46         case ELF_RELOC_REL:
47                 rel = (const Elf_Rel *)data;
48                 where = (Elf_Addr *) (relocbase + rel->r_offset);
49                 addend = *where;
50                 rtype = ELF_R_TYPE(rel->r_info);
51                 break;
52         case ELF_RELOC_RELA:
53                 rela = (const Elf_Rela *)data;
54                 where = (Elf_Addr *) (relocbase + rela->r_offset);
55                 addend = rela->r_addend;
56                 rtype = ELF_R_TYPE(rela->r_info);
57                 break;
58         default:
59                 panic("unknown reloc type %d\n", type);
60         }
61
62         switch (rtype) {
63
64                 case R_386_NONE:        /* none */
65                         break;
66
67                 case R_386_32:          /* S + A */
68                         if (sym == NULL)
69                                 return -1;
70                         addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
71                         if (addr == 0)
72                                 return -1;
73                         addr += addend;
74                         if (*where != addr)
75                                 *where = addr;
76                         break;
77
78                 case R_386_PC32:        /* S + A - P */
79                         if (sym == NULL)
80                                 return -1;
81                         addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
82                         if (addr == 0)
83                                 return -1;
84                         addr += addend - (Elf_Addr)where;
85                         if (*where != addr)
86                                 *where = addr;
87                         break;
88
89                 case R_386_COPY:        /* none */
90                         /*
91                          * There shouldn't be copy relocations in kernel
92                          * objects.
93                          */
94                         printf("kldload: unexpected R_COPY relocation\n");
95                         return -1;
96                         break;
97
98                 case R_386_GLOB_DAT:    /* S */
99                         if (sym == NULL)
100                                 return -1;
101                         addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
102                         if (addr == 0)
103                                 return -1;
104                         if (*where != addr)
105                                 *where = addr;
106                         break;
107
108                 case R_386_RELATIVE:    /* B + A */
109                         addr = relocbase + addend;
110                         if (*where != addr)
111                                 *where = addr;
112                         break;
113
114                 default:
115                         printf("kldload: unexpected relocation type %d\n",
116                                rtype);
117                         return -1;
118         }
119         return(0);
120 }