mdreloc.c revision 1.4 1 /* $NetBSD: mdreloc.c,v 1.4 2001/12/14 22:07:23 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Frank van der Linden for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <sys/types.h>
39 #include <sys/mman.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <elf.h>
49
50 #include "debug.h"
51 #include "rtld.h"
52
53 extern Elf64_Addr _GLOBAL_OFFSET_TABLE_[];
54
55 int
56 _rtld_relocate_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, bool dodebug)
57 {
58 Elf64_Addr *where64;
59 Elf32_Addr *where32;
60 const Elf_Sym *def;
61 const Obj_Entry *defobj;
62 Elf64_Addr tmp64;
63 Elf32_Addr tmp32;
64
65 where64 = (Elf64_Addr *)(obj->relocbase + rela->r_offset);
66 where32 = (Elf32_Addr *)where64;
67
68 switch (ELF_R_TYPE(rela->r_info)) {
69
70 case R_TYPE(NONE):
71 break;
72
73 case R_TYPE(32): /* word32 S + A, truncate */
74 case R_TYPE(32S): /* word32 S + A, signed truncate */
75 case R_TYPE(GOT32): /* word32 G + A (XXX can we see these?) */
76 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
77 &defobj, false);
78 if (def == NULL)
79 return -1;
80 tmp32 = (Elf32_Addr)(u_long)(defobj->relocbase + def->st_value +
81 rela->r_addend);
82
83 if (*where32 != tmp32)
84 *where32 = tmp32;
85 rdbg(dodebug, ("32/32S %s in %s --> %p in %s",
86 defobj->strtab + def->st_name, obj->path,
87 (void *)(unsigned long)*where32, defobj->path));
88 break;
89 case R_TYPE(64): /* word64 S + A */
90 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
91 &defobj, false);
92 if (def == NULL)
93 return -1;
94
95 tmp64 = (Elf64_Addr)(defobj->relocbase + def->st_value +
96 rela->r_addend);
97
98 if (*where64 != tmp64)
99 *where64 = tmp64;
100 rdbg(dodebug, ("64 %s in %s --> %p in %s",
101 defobj->strtab + def->st_name, obj->path,
102 (void *)*where64, defobj->path));
103 break;
104 case R_TYPE(PC32): /* word32 S + A - P */
105 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
106 &defobj, false);
107 if (def == NULL)
108 return -1;
109 tmp32 = (Elf32_Addr)(u_long)(defobj->relocbase + def->st_value +
110 rela->r_addend - (Elf64_Addr)where64);
111 if (*where32 != tmp32)
112 *where32 = tmp32;
113 rdbg(dodebug, ("PC32 %s in %s --> %p in %s",
114 defobj->strtab + def->st_name, obj->path,
115 (void *)(unsigned long)*where32, defobj->path));
116 break;
117 case R_TYPE(GLOB_DAT): /* word64 S */
118 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
119 &defobj, false);
120 if (def == NULL)
121 return -1;
122
123 tmp64 = (Elf64_Addr)(defobj->relocbase + def->st_value);
124
125 if (*where64 != tmp64)
126 *where64 = tmp64;
127 rdbg(dodebug, ("64 %s in %s --> %p in %s",
128 defobj->strtab + def->st_name, obj->path,
129 (void *)*where64, defobj->path));
130 break;
131 case R_TYPE(RELATIVE): /* word64 B + A */
132 tmp64 = (Elf64_Addr)(obj->relocbase + rela->r_addend);
133 if (*where64 != tmp64)
134 *where64 = tmp64;
135 rdbg(dodebug, ("RELATIVE in %s --> %p", obj->path,
136 (void *)*where64));
137 break;
138
139 case R_TYPE(COPY):
140 rdbg(dodebug, ("COPY"));
141 break;
142
143 default:
144 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
145 &defobj, true);
146 rdbg(dodebug, ("sym = %lu, type = %lu, offset = %p, "
147 "addend = %p, contents = %p, symbol = %s",
148 (u_long)ELF_R_SYM(rela->r_info),
149 (u_long)ELF_R_TYPE(rela->r_info),
150 (void *)rela->r_offset, (void *)rela->r_addend,
151 (void *)*where64,
152 def ? defobj->strtab + def->st_name : "??"));
153 _rtld_error("%s: Unsupported relocation type %ld "
154 "in non-PLT relocations\n",
155 obj->path, (u_long) ELF_R_TYPE(rela->r_info));
156 return -1;
157 }
158 return 0;
159 }
160
161
162
163 int
164 _rtld_relocate_plt_object(Obj_Entry *obj, const Elf_Rela *rela, caddr_t *addrp,
165 bool bind_now, bool dodebug)
166 {
167 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
168 Elf_Addr new_value;
169
170 /* Fully resolve procedure addresses now */
171
172 if (bind_now || obj->pltgot == NULL) {
173 const Elf_Sym *def;
174 const Obj_Entry *defobj;
175
176 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT));
177
178 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
179 &defobj, true);
180 if (def == NULL)
181 return -1;
182
183 new_value = (Elf_Addr)
184 (defobj->relocbase + def->st_value + rela->r_addend);
185 rdbg(dodebug, ("bind now %d/fixup in %s --> old=%p new=%p",
186 (int)bind_now,
187 defobj->strtab + def->st_name,
188 (void *)*where, (void *)new_value));
189 } else {
190 if (!obj->mainprog) {
191 /* Just relocate the GOT slots pointing into the PLT */
192 new_value = *where + (Elf_Addr) obj->relocbase;
193 rdbg(dodebug, ("fixup !main in %s --> %p", obj->path,
194 (void *)(unsigned long)*where));
195 } else {
196 return 0;
197 }
198 }
199 /*
200 * Since this page is probably copy-on-write, let's not write
201 * it unless we really really have to.
202 */
203 if (*where != new_value)
204 *where = new_value;
205 if (addrp != NULL)
206 *addrp = *(caddr_t *)(obj->relocbase + rela->r_offset) -
207 rela->r_addend;
208 return 0;
209 }
210