Merge from vendor branch READLINE:
[dragonfly.git] / libexec / rtld-elf / i386 / reloc.c
1 /*-
2  * Copyright 1996, 1997, 1998, 1999 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/libexec/rtld-elf/i386/reloc.c,v 1.6.2.2 2002/06/16 20:02:09 dillon Exp $
26  * $DragonFly: src/libexec/rtld-elf/i386/reloc.c,v 1.2 2003/06/17 04:27:08 dillon Exp $
27  */
28
29 /*
30  * Dynamic linker for ELF.
31  *
32  * John Polstra <jdp@polstra.com>.
33  */
34
35 #include <sys/param.h>
36 #include <sys/mman.h>
37
38 #include <dlfcn.h>
39 #include <err.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include "debug.h"
49 #include "rtld.h"
50
51 /*
52  * Process the special R_386_COPY relocations in the main program.  These
53  * copy data from a shared object into a region in the main program's BSS
54  * segment.
55  *
56  * Returns 0 on success, -1 on failure.
57  */
58 int
59 do_copy_relocations(Obj_Entry *dstobj)
60 {
61     const Elf_Rel *rellim;
62     const Elf_Rel *rel;
63
64     assert(dstobj->mainprog);   /* COPY relocations are invalid elsewhere */
65
66     rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
67     for (rel = dstobj->rel;  rel < rellim;  rel++) {
68         if (ELF_R_TYPE(rel->r_info) == R_386_COPY) {
69             void *dstaddr;
70             const Elf_Sym *dstsym;
71             const char *name;
72             unsigned long hash;
73             size_t size;
74             const void *srcaddr;
75             const Elf_Sym *srcsym;
76             Obj_Entry *srcobj;
77
78             dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
79             dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
80             name = dstobj->strtab + dstsym->st_name;
81             hash = elf_hash(name);
82             size = dstsym->st_size;
83
84             for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
85                 if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL)
86                     break;
87
88             if (srcobj == NULL) {
89                 _rtld_error("Undefined symbol \"%s\" referenced from COPY"
90                   " relocation in %s", name, dstobj->path);
91                 return -1;
92             }
93
94             srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
95             memcpy(dstaddr, srcaddr, size);
96         }
97     }
98
99     return 0;
100 }
101
102 /* Initialize the special GOT entries. */
103 void
104 init_pltgot(Obj_Entry *obj)
105 {
106     if (obj->pltgot != NULL) {
107         obj->pltgot[1] = (Elf_Addr) obj;
108         obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
109     }
110 }
111
112 /* Process the non-PLT relocations. */
113 int
114 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
115 {
116         const Elf_Rel *rellim;
117         const Elf_Rel *rel;
118         SymCache *cache;
119         int bytes = obj->nchains * sizeof(SymCache);
120         int r = -1;
121
122         /*
123          * The dynamic loader may be called from a thread, we have
124          * limited amounts of stack available so we cannot use alloca().
125          */
126         cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
127         if (cache == MAP_FAILED)
128             cache = NULL;
129         if (cache != NULL)
130             memset(cache, 0, bytes);
131
132         rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
133         for (rel = obj->rel;  rel < rellim;  rel++) {
134             Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
135
136             switch (ELF_R_TYPE(rel->r_info)) {
137
138             case R_386_NONE:
139                 break;
140
141             case R_386_32:
142                 {
143                     const Elf_Sym *def;
144                     const Obj_Entry *defobj;
145
146                     def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
147                       false, cache);
148                     if (def == NULL)
149                         goto done;
150
151                     *where += (Elf_Addr) (defobj->relocbase + def->st_value);
152                 }
153                 break;
154
155             case R_386_PC32:
156                 /*
157                  * I don't think the dynamic linker should ever see this
158                  * type of relocation.  But the binutils-2.6 tools sometimes
159                  * generate it.
160                  */
161                 {
162                     const Elf_Sym *def;
163                     const Obj_Entry *defobj;
164
165                     def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
166                       false, cache);
167                     if (def == NULL)
168                         goto done;
169
170                     *where +=
171                       (Elf_Addr) (defobj->relocbase + def->st_value) -
172                       (Elf_Addr) where;
173                 }
174                 break;
175
176             case R_386_COPY:
177                 /*
178                  * These are deferred until all other relocations have
179                  * been done.  All we do here is make sure that the COPY
180                  * relocation is not in a shared library.  They are allowed
181                  * only in executable files.
182                  */
183                 if (!obj->mainprog) {
184                     _rtld_error("%s: Unexpected R_386_COPY relocation"
185                       " in shared library", obj->path);
186                     goto done;
187                 }
188                 break;
189
190             case R_386_GLOB_DAT:
191                 {
192                     const Elf_Sym *def;
193                     const Obj_Entry *defobj;
194
195                     def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
196                       false, cache);
197                     if (def == NULL)
198                         goto done;
199
200                     *where = (Elf_Addr) (defobj->relocbase + def->st_value);
201                 }
202                 break;
203
204             case R_386_RELATIVE:
205                 *where += (Elf_Addr) obj->relocbase;
206                 break;
207
208             default:
209                 _rtld_error("%s: Unsupported relocation type %d"
210                   " in non-PLT relocations\n", obj->path,
211                   ELF_R_TYPE(rel->r_info));
212                 goto done;
213             }
214         }
215         r = 0;
216 done:
217         if (cache)
218             munmap(cache, bytes);
219         return(r);
220 }
221
222 /* Process the PLT relocations. */
223 int
224 reloc_plt(Obj_Entry *obj)
225 {
226     const Elf_Rel *rellim;
227     const Elf_Rel *rel;
228
229     rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
230     for (rel = obj->pltrel;  rel < rellim;  rel++) {
231         Elf_Addr *where;
232
233         assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
234
235         /* Relocate the GOT slot pointing into the PLT. */
236         where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
237         *where += (Elf_Addr)obj->relocbase;
238     }
239     return 0;
240 }
241
242 /* Relocate the jump slots in an object. */
243 int
244 reloc_jmpslots(Obj_Entry *obj)
245 {
246     const Elf_Rel *rellim;
247     const Elf_Rel *rel;
248
249     if (obj->jmpslots_done)
250         return 0;
251     rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
252     for (rel = obj->pltrel;  rel < rellim;  rel++) {
253         Elf_Addr *where;
254         const Elf_Sym *def;
255         const Obj_Entry *defobj;
256
257         assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
258         where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
259         def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL);
260         if (def == NULL)
261             return -1;
262         reloc_jmpslot(where, (Elf_Addr)(defobj->relocbase + def->st_value));
263     }
264     obj->jmpslots_done = true;
265     return 0;
266 }