mdreloc.c revision 1.2 1 #include <sys/types.h>
2 #include <sys/mman.h>
3 #include <err.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <elf.h>
12
13 #include "debug.h"
14 #include "rtld.h"
15
16 extern Elf64_Addr _GLOBAL_OFFSET_TABLE_[];
17
18 int
19 _rtld_relocate_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, bool dodebug)
20 {
21 Elf64_Addr *where64;
22 Elf32_Addr *where32;
23 const Elf_Sym *def;
24 const Obj_Entry *defobj;
25 Elf64_Addr tmp64;
26 Elf32_Addr tmp32;
27
28 where64 = (Elf64_Addr *)(obj->relocbase + rela->r_offset);
29 where32 = (Elf32_Addr *)where64;
30
31 switch (ELF_R_TYPE(rela->r_info)) {
32
33 case R_TYPE(NONE):
34 break;
35
36 case R_TYPE(32): /* word32 S + A, truncate */
37 case R_TYPE(32S): /* word32 S + A, signed truncate */
38 case R_TYPE(GOT32): /* word32 G + A (XXX can we see these?) */
39 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
40 &defobj, false);
41 if (def == NULL)
42 return -1;
43 tmp32 = (Elf32_Addr)(u_long)(defobj->relocbase + def->st_value +
44 rela->r_addend);
45
46 if (*where32 != tmp32)
47 *where32 = tmp32;
48 rdbg(dodebug, ("32/32S %s in %s --> %p in %s",
49 defobj->strtab + def->st_name, obj->path,
50 (void *)(unsigned long)*where32, defobj->path));
51 break;
52 case R_TYPE(64): /* word64 S + A */
53 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
54 &defobj, false);
55 if (def == NULL)
56 return -1;
57
58 tmp64 = (Elf64_Addr)(defobj->relocbase + def->st_value +
59 rela->r_addend);
60
61 if (*where64 != tmp64)
62 *where64 = tmp64;
63 rdbg(dodebug, ("64 %s in %s --> %p in %s",
64 defobj->strtab + def->st_name, obj->path,
65 (void *)*where64, defobj->path));
66 break;
67 case R_TYPE(PC32): /* word32 S + A - P */
68 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
69 &defobj, false);
70 if (def == NULL)
71 return -1;
72 tmp32 = (Elf32_Addr)(u_long)(defobj->relocbase + def->st_value +
73 rela->r_addend - (Elf64_Addr)where64);
74 if (*where32 != tmp32)
75 *where32 = tmp32;
76 rdbg(dodebug, ("PC32 %s in %s --> %p in %s",
77 defobj->strtab + def->st_name, obj->path,
78 (void *)(unsigned long)*where32, defobj->path));
79 break;
80 case R_TYPE(GLOB_DAT): /* word64 S */
81 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
82 &defobj, false);
83 if (def == NULL)
84 return -1;
85
86 tmp64 = (Elf64_Addr)(defobj->relocbase + def->st_value);
87
88 if (*where64 != tmp64)
89 *where64 = tmp64;
90 rdbg(dodebug, ("64 %s in %s --> %p in %s",
91 defobj->strtab + def->st_name, obj->path,
92 (void *)*where64, defobj->path));
93 break;
94 case R_TYPE(RELATIVE): /* word64 B + A */
95 tmp64 = (Elf64_Addr)(obj->relocbase + rela->r_addend);
96 if (*where64 != tmp64)
97 *where64 = tmp64;
98 rdbg(dodebug, ("RELATIVE in %s --> %p", obj->path,
99 (void *)*where64));
100 break;
101
102 case R_TYPE(COPY):
103 rdbg(dodebug, ("COPY"));
104 break;
105
106 default:
107 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
108 &defobj, true);
109 rdbg(dodebug, ("sym = %lu, type = %lu, offset = %p, "
110 "addend = %p, contents = %p, symbol = %s",
111 (u_long)ELF_R_SYM(rela->r_info),
112 (u_long)ELF_R_TYPE(rela->r_info),
113 (void *)rela->r_offset, (void *)rela->r_addend,
114 (void *)*where64,
115 def ? defobj->strtab + def->st_name : "??"));
116 _rtld_error("%s: Unsupported relocation type %ld "
117 "in non-PLT relocations\n",
118 obj->path, (u_long) ELF_R_TYPE(rela->r_info));
119 return -1;
120 }
121 return 0;
122 }
123
124
125
126 int
127 _rtld_relocate_plt_object(Obj_Entry *obj, const Elf_Rela *rela, caddr_t *addrp,
128 bool bind_now, bool dodebug)
129 {
130 Elf32_Addr *where = (Elf32_Addr *)(obj->relocbase + rela->r_offset);
131 Elf32_Addr new_value;
132
133 /* Fully resolve procedure addresses now */
134
135 if (bind_now || obj->pltgot == NULL) {
136 const Elf_Sym *def;
137 const Obj_Entry *defobj;
138
139 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT));
140
141 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
142 &defobj, true);
143 if (def == NULL)
144 return -1;
145
146 new_value = (Elf32_Addr)(u_long)
147 (defobj->relocbase + def->st_value + rela->r_addend);
148 rdbg(dodebug, ("bind now %d/fixup in %s --> old=%p new=%p",
149 (int)bind_now,
150 defobj->strtab + def->st_name,
151 (void *)(u_long)*where, (void *)(u_long)new_value));
152 } else {
153 if (!obj->mainprog) {
154 /* Just relocate the GOT slots pointing into the PLT */
155 new_value = *where + (Elf32_Addr)(u_long)
156 obj->relocbase;
157 rdbg(dodebug, ("fixup !main in %s --> %p", obj->path,
158 (void *)(unsigned long)*where));
159 } else {
160 return 0;
161 }
162 }
163 /*
164 * Since this page is probably copy-on-write, let's not write
165 * it unless we really really have to.
166 */
167 if (*where != new_value)
168 *where = new_value;
169 if (addrp != NULL)
170 *addrp = *(caddr_t *)(obj->relocbase + rela->r_offset) -
171 rela->r_addend;
172 return 0;
173 }
174