| @@ -1,661 +1,661 @@ | | | @@ -1,661 +1,661 @@ |
1 | /* $NetBSD: hppa_reloc.c,v 1.40 2011/09/25 13:34:54 chs Exp $ */ | | 1 | /* $NetBSD: hppa_reloc.c,v 1.41 2011/12/04 16:53:08 skrll Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2002, 2004 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2002, 2004 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Matt Fredette and Nick Hudson. | | 8 | * by Matt Fredette and Nick Hudson. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | #ifndef lint | | 33 | #ifndef lint |
34 | __RCSID("$NetBSD: hppa_reloc.c,v 1.40 2011/09/25 13:34:54 chs Exp $"); | | 34 | __RCSID("$NetBSD: hppa_reloc.c,v 1.41 2011/12/04 16:53:08 skrll Exp $"); |
35 | #endif /* not lint */ | | 35 | #endif /* not lint */ |
36 | | | 36 | |
37 | #include <stdlib.h> | | 37 | #include <stdlib.h> |
38 | #include <sys/types.h> | | 38 | #include <sys/types.h> |
39 | #include <sys/queue.h> | | 39 | #include <sys/queue.h> |
40 | | | 40 | |
41 | #include <string.h> | | 41 | #include <string.h> |
42 | | | 42 | |
43 | #include "rtld.h" | | 43 | #include "rtld.h" |
44 | #include "debug.h" | | 44 | #include "debug.h" |
45 | | | 45 | |
46 | #ifdef RTLD_DEBUG_HPPA | | 46 | #ifdef RTLD_DEBUG_HPPA |
47 | #define hdbg(x) xprintf x | | 47 | #define hdbg(x) xprintf x |
48 | #else | | 48 | #else |
49 | #define hdbg(x) /* nothing */ | | 49 | #define hdbg(x) /* nothing */ |
50 | #endif | | 50 | #endif |
51 | | | 51 | |
52 | caddr_t _rtld_bind(const Obj_Entry *, const Elf_Addr); | | 52 | caddr_t _rtld_bind(const Obj_Entry *, const Elf_Addr); |
53 | void _rtld_bind_start(void); | | 53 | void _rtld_bind_start(void); |
54 | void __rtld_setup_hppa_pltgot(const Obj_Entry *, Elf_Addr *); | | 54 | void __rtld_setup_hppa_pltgot(const Obj_Entry *, Elf_Addr *); |
55 | | | 55 | |
56 | /* | | 56 | /* |
57 | * It is possible for the compiler to emit relocations for unaligned data. | | 57 | * It is possible for the compiler to emit relocations for unaligned data. |
58 | * We handle this situation with these inlines. | | 58 | * We handle this situation with these inlines. |
59 | */ | | 59 | */ |
60 | #define RELOC_ALIGNED_P(x) \ | | 60 | #define RELOC_ALIGNED_P(x) \ |
61 | (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) | | 61 | (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) |
62 | | | 62 | |
63 | static inline Elf_Addr | | 63 | static inline Elf_Addr |
64 | load_ptr(void *where) | | 64 | load_ptr(void *where) |
65 | { | | 65 | { |
66 | if (__predict_true(RELOC_ALIGNED_P(where))) | | 66 | if (__predict_true(RELOC_ALIGNED_P(where))) |
67 | return *(Elf_Addr *)where; | | 67 | return *(Elf_Addr *)where; |
68 | else { | | 68 | else { |
69 | Elf_Addr res; | | 69 | Elf_Addr res; |
70 | | | 70 | |
71 | (void)memcpy(&res, where, sizeof(res)); | | 71 | (void)memcpy(&res, where, sizeof(res)); |
72 | return res; | | 72 | return res; |
73 | } | | 73 | } |
74 | } | | 74 | } |
75 | | | 75 | |
76 | static inline void | | 76 | static inline void |
77 | store_ptr(void *where, Elf_Addr val) | | 77 | store_ptr(void *where, Elf_Addr val) |
78 | { | | 78 | { |
79 | if (__predict_true(RELOC_ALIGNED_P(where))) | | 79 | if (__predict_true(RELOC_ALIGNED_P(where))) |
80 | *(Elf_Addr *)where = val; | | 80 | *(Elf_Addr *)where = val; |
81 | else | | 81 | else |
82 | (void)memcpy(where, &val, sizeof(val)); | | 82 | (void)memcpy(where, &val, sizeof(val)); |
83 | } | | 83 | } |
84 | | | 84 | |
85 | /* | | 85 | /* |
86 | * In the runtime architecture (ABI), PLABEL function pointers are | | 86 | * In the runtime architecture (ABI), PLABEL function pointers are |
87 | * distinguished from normal function pointers by having the next-least- | | 87 | * distinguished from normal function pointers by having the next-least- |
88 | * significant bit set. (This bit is referred to as the L field in HP | | 88 | * significant bit set. (This bit is referred to as the L field in HP |
89 | * documentation). The $$dyncall millicode is aware of this. | | 89 | * documentation). The $$dyncall millicode is aware of this. |
90 | */ | | 90 | */ |
91 | #define RTLD_MAKE_PLABEL(plabel) (((Elf_Addr)(plabel)) | (1 << 1)) | | 91 | #define RTLD_MAKE_PLABEL(plabel) (((Elf_Addr)(plabel)) | (1 << 1)) |
92 | #define RTLD_IS_PLABEL(addr) (((Elf_Addr)(addr)) & (1 << 1)) | | 92 | #define RTLD_IS_PLABEL(addr) (((Elf_Addr)(addr)) & (1 << 1)) |
93 | #define RTLD_GET_PLABEL(addr) ((hppa_plabel *) (((Elf_Addr)addr) & ~3)) | | 93 | #define RTLD_GET_PLABEL(addr) ((hppa_plabel *) (((Elf_Addr)addr) & ~3)) |
94 | | | 94 | |
95 | /* | | 95 | /* |
96 | * This is the PLABEL structure. The function PC and | | 96 | * This is the PLABEL structure. The function PC and |
97 | * shared linkage members must come first, as they are | | 97 | * shared linkage members must come first, as they are |
98 | * the actual PLABEL. | | 98 | * the actual PLABEL. |
99 | */ | | 99 | */ |
100 | typedef struct _hppa_plabel { | | 100 | typedef struct _hppa_plabel { |
101 | Elf_Addr hppa_plabel_pc; | | 101 | Elf_Addr hppa_plabel_pc; |
102 | Elf_Addr hppa_plabel_sl; | | 102 | Elf_Addr hppa_plabel_sl; |
103 | SLIST_ENTRY(_hppa_plabel) hppa_plabel_next; | | 103 | SLIST_ENTRY(_hppa_plabel) hppa_plabel_next; |
104 | } hppa_plabel; | | 104 | } hppa_plabel; |
105 | | | 105 | |
106 | /* | | 106 | /* |
107 | * For now allocated PLABEL structures are tracked on a | | 107 | * For now allocated PLABEL structures are tracked on a |
108 | * singly linked list. This maybe should be revisited. | | 108 | * singly linked list. This maybe should be revisited. |
109 | */ | | 109 | */ |
110 | static SLIST_HEAD(hppa_plabel_head, _hppa_plabel) hppa_plabel_list | | 110 | static SLIST_HEAD(hppa_plabel_head, _hppa_plabel) hppa_plabel_list |
111 | = SLIST_HEAD_INITIALIZER(hppa_plabel_list); | | 111 | = SLIST_HEAD_INITIALIZER(hppa_plabel_list); |
112 | | | 112 | |
113 | /* | | 113 | /* |
114 | * Because I'm hesitant to use NEW while relocating self, | | 114 | * Because I'm hesitant to use NEW while relocating self, |
115 | * this is a small pool of preallocated PLABELs. | | 115 | * this is a small pool of preallocated PLABELs. |
116 | */ | | 116 | */ |
117 | #define HPPA_PLABEL_PRE (32) | | 117 | #define HPPA_PLABEL_PRE (32) |
118 | static hppa_plabel hppa_plabel_pre[HPPA_PLABEL_PRE]; | | 118 | static hppa_plabel hppa_plabel_pre[HPPA_PLABEL_PRE]; |
119 | static int hppa_plabel_pre_next = 0; | | 119 | static int hppa_plabel_pre_next = 0; |
120 | | | 120 | |
121 | void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); | | 121 | void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); |
122 | int _rtld_relocate_plt_objects(const Obj_Entry *); | | 122 | int _rtld_relocate_plt_objects(const Obj_Entry *); |
123 | static inline int _rtld_relocate_plt_object(const Obj_Entry *, | | 123 | static inline int _rtld_relocate_plt_object(const Obj_Entry *, |
124 | const Elf_Rela *, Elf_Addr *); | | 124 | const Elf_Rela *, Elf_Addr *); |
125 | | | 125 | |
126 | /* | | 126 | /* |
127 | * This bootstraps the dynamic linker by relocating its GOT. | | 127 | * This bootstraps the dynamic linker by relocating its GOT. |
128 | * On the hppa, unlike on other architectures, static strings | | 128 | * On the hppa, unlike on other architectures, static strings |
129 | * are found through the GOT. Static strings are essential | | 129 | * are found through the GOT. Static strings are essential |
130 | * for RTLD_DEBUG, and I suspect they're used early even when | | 130 | * for RTLD_DEBUG, and I suspect they're used early even when |
131 | * !defined(RTLD_DEBUG), making relocating the GOT essential. | | 131 | * !defined(RTLD_DEBUG), making relocating the GOT essential. |
132 | * | | 132 | * |
133 | * It gets worse. Relocating the GOT doesn't mean just walking | | 133 | * It gets worse. Relocating the GOT doesn't mean just walking |
134 | * it and adding the relocbase to all of the entries. You must | | 134 | * it and adding the relocbase to all of the entries. You must |
135 | * find and use the GOT relocations, since those RELA relocations | | 135 | * find and use the GOT relocations, since those RELA relocations |
136 | * have the necessary addends - the GOT comes initialized as | | 136 | * have the necessary addends - the GOT comes initialized as |
137 | * zeroes. | | 137 | * zeroes. |
138 | */ | | 138 | */ |
139 | void | | 139 | void |
140 | _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) | | 140 | _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) |
141 | { | | 141 | { |
142 | const Elf_Rela *relafirst, *rela, *relalim; | | 142 | const Elf_Rela *relafirst, *rela, *relalim; |
143 | Elf_Addr relasz; | | 143 | Elf_Addr relasz; |
144 | void *where; | | 144 | void *where; |
145 | Elf_Addr *pltgot; | | 145 | Elf_Addr *pltgot; |
146 | const Elf_Rela *plabel_relocs[HPPA_PLABEL_PRE]; | | 146 | const Elf_Rela *plabel_relocs[HPPA_PLABEL_PRE]; |
147 | int nplabel_relocs = 0; | | 147 | int nplabel_relocs = 0; |
148 | int i; | | 148 | int i; |
149 | const Elf_Sym *symtab, *sym; | | 149 | const Elf_Sym *symtab, *sym; |
150 | unsigned long symnum; | | 150 | unsigned long symnum; |
151 | hppa_plabel *plabel; | | 151 | hppa_plabel *plabel; |
152 | | | 152 | |
153 | /* | | 153 | /* |
154 | * Process the DYNAMIC section, looking for the non-PLT relocations. | | 154 | * Process the DYNAMIC section, looking for the non-PLT relocations. |
155 | */ | | 155 | */ |
156 | relafirst = NULL; | | 156 | relafirst = NULL; |
157 | relasz = 0; | | 157 | relasz = 0; |
158 | symtab = NULL; | | 158 | symtab = NULL; |
159 | pltgot = NULL; | | 159 | pltgot = NULL; |
160 | for (; dynp->d_tag != DT_NULL; ++dynp) { | | 160 | for (; dynp->d_tag != DT_NULL; ++dynp) { |
161 | switch (dynp->d_tag) { | | 161 | switch (dynp->d_tag) { |
162 | | | 162 | |
163 | case DT_RELA: | | 163 | case DT_RELA: |
164 | relafirst = (const Elf_Rela *) | | 164 | relafirst = (const Elf_Rela *) |
165 | (relocbase + dynp->d_un.d_ptr); | | 165 | (relocbase + dynp->d_un.d_ptr); |
166 | break; | | 166 | break; |
167 | | | 167 | |
168 | case DT_RELASZ: | | 168 | case DT_RELASZ: |
169 | relasz = dynp->d_un.d_val; | | 169 | relasz = dynp->d_un.d_val; |
170 | break; | | 170 | break; |
171 | | | 171 | |
172 | case DT_SYMTAB: | | 172 | case DT_SYMTAB: |
173 | symtab = (const Elf_Sym *) | | 173 | symtab = (const Elf_Sym *) |
174 | (relocbase + dynp->d_un.d_ptr); | | 174 | (relocbase + dynp->d_un.d_ptr); |
175 | break; | | 175 | break; |
176 | | | 176 | |
177 | case DT_PLTGOT: | | 177 | case DT_PLTGOT: |
178 | pltgot = (Elf_Addr *) | | 178 | pltgot = (Elf_Addr *) |
179 | (relocbase + dynp->d_un.d_ptr); | | 179 | (relocbase + dynp->d_un.d_ptr); |
180 | break; | | 180 | break; |
181 | } | | 181 | } |
182 | } | | 182 | } |
183 | relalim = (const Elf_Rela *)((const char *)relafirst + relasz); | | 183 | relalim = (const Elf_Rela *)((const char *)relafirst + relasz); |
184 | | | 184 | |
185 | for (rela = relafirst; rela < relalim; rela++) { | | 185 | for (rela = relafirst; rela < relalim; rela++) { |
186 | symnum = ELF_R_SYM(rela->r_info); | | 186 | symnum = ELF_R_SYM(rela->r_info); |
187 | where = (void *)(relocbase + rela->r_offset); | | 187 | where = (void *)(relocbase + rela->r_offset); |
188 | | | 188 | |
189 | switch (ELF_R_TYPE(rela->r_info)) { | | 189 | switch (ELF_R_TYPE(rela->r_info)) { |
190 | case R_TYPE(DIR32): | | 190 | case R_TYPE(DIR32): |
191 | if (symnum == 0) | | 191 | if (symnum == 0) |
192 | store_ptr(where, | | 192 | store_ptr(where, |
193 | relocbase + rela->r_addend); | | 193 | relocbase + rela->r_addend); |
194 | else { | | 194 | else { |
195 | sym = symtab + symnum; | | 195 | sym = symtab + symnum; |
196 | store_ptr(where, | | 196 | store_ptr(where, |
197 | relocbase + rela->r_addend + sym->st_value); | | 197 | relocbase + rela->r_addend + sym->st_value); |
198 | } | | 198 | } |
199 | break; | | 199 | break; |
200 | | | 200 | |
201 | case R_TYPE(PLABEL32): | | 201 | case R_TYPE(PLABEL32): |
202 | /* | | 202 | /* |
203 | * PLABEL32 relocation processing is done in two phases | | 203 | * PLABEL32 relocation processing is done in two phases |
204 | * | | 204 | * |
205 | * i) local function relocations (symbol number == 0) | | 205 | * i) local function relocations (symbol number == 0) |
206 | * can be resolved immediately. | | 206 | * can be resolved immediately. |
207 | * | | 207 | * |
208 | * ii) external function relocations are deferred until | | 208 | * ii) external function relocations are deferred until |
209 | * we finish all other relocations so that global | | 209 | * we finish all other relocations so that global |
210 | * data isn't accessed until all other non-PLT | | 210 | * data isn't accessed until all other non-PLT |
211 | * relocations have been done. | | 211 | * relocations have been done. |
212 | */ | | 212 | */ |
213 | if (symnum == 0) | | 213 | if (symnum == 0) |
214 | *((Elf_Addr *)where) = | | 214 | *((Elf_Addr *)where) = |
215 | relocbase + rela->r_addend; | | 215 | relocbase + rela->r_addend; |
216 | else | | 216 | else |
217 | plabel_relocs[nplabel_relocs++] = rela; | | 217 | plabel_relocs[nplabel_relocs++] = rela; |
218 | break; | | 218 | break; |
219 | | | 219 | |
220 | default: | | 220 | default: |
221 | break; | | 221 | break; |
222 | } | | 222 | } |
223 | } | | 223 | } |
224 | | | 224 | |
225 | assert(nplabel_relocs < HPPA_PLABEL_PRE); | | 225 | assert(nplabel_relocs < HPPA_PLABEL_PRE); |
226 | for (i = 0; i < nplabel_relocs; i++) { | | 226 | for (i = 0; i < nplabel_relocs; i++) { |
227 | rela = plabel_relocs[i]; | | 227 | rela = plabel_relocs[i]; |
228 | where = (void *)(relocbase + rela->r_offset); | | 228 | where = (void *)(relocbase + rela->r_offset); |
229 | sym = symtab + ELF_R_SYM(rela->r_info); | | 229 | sym = symtab + ELF_R_SYM(rela->r_info); |
230 | | | 230 | |
231 | plabel = &hppa_plabel_pre[hppa_plabel_pre_next++]; | | 231 | plabel = &hppa_plabel_pre[hppa_plabel_pre_next++]; |
232 | | | 232 | |
233 | plabel->hppa_plabel_pc = (Elf_Addr) | | 233 | plabel->hppa_plabel_pc = (Elf_Addr) |
234 | (relocbase + sym->st_value + rela->r_addend); | | 234 | (relocbase + sym->st_value + rela->r_addend); |
235 | plabel->hppa_plabel_sl = (Elf_Addr)pltgot; | | 235 | plabel->hppa_plabel_sl = (Elf_Addr)pltgot; |
236 | | | 236 | |
237 | SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next); | | 237 | SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next); |
238 | *((Elf_Addr *)where) = (Elf_Addr)(RTLD_MAKE_PLABEL(plabel)); | | 238 | *((Elf_Addr *)where) = (Elf_Addr)(RTLD_MAKE_PLABEL(plabel)); |
239 | } | | 239 | } |
240 | | | 240 | |
241 | #if defined(RTLD_DEBUG_HPPA) | | 241 | #if defined(RTLD_DEBUG_HPPA) |
242 | for (rela = relafirst; rela < relalim; rela++) { | | 242 | for (rela = relafirst; rela < relalim; rela++) { |
243 | where = (void *)(relocbase + rela->r_offset); | | 243 | where = (void *)(relocbase + rela->r_offset); |
244 | | | 244 | |
245 | switch (ELF_R_TYPE(rela->r_info)) { | | 245 | switch (ELF_R_TYPE(rela->r_info)) { |
246 | case R_TYPE(DIR32): | | 246 | case R_TYPE(DIR32): |
247 | hdbg(("DIR32 rela @%p(%p) -> %p(%p)\n", | | 247 | hdbg(("DIR32 rela @%p(%p) -> %p(%p)\n", |
248 | (void *)rela->r_offset, | | 248 | (void *)rela->r_offset, |
249 | (void *)where, | | 249 | (void *)where, |
250 | (void *)rela->r_addend, | | 250 | (void *)rela->r_addend, |
251 | (void *)*((Elf_Addr *)where) )); | | 251 | (void *)*((Elf_Addr *)where) )); |
252 | break; | | 252 | break; |
253 | | | 253 | |
254 | case R_TYPE(PLABEL32): | | 254 | case R_TYPE(PLABEL32): |
255 | symnum = ELF_R_SYM(rela->r_info); | | 255 | symnum = ELF_R_SYM(rela->r_info); |
256 | if (symnum == 0) { | | 256 | if (symnum == 0) { |
257 | hdbg(("PLABEL rela @%p(%p) -> %p(%p)\n", | | 257 | hdbg(("PLABEL rela @%p(%p) -> %p(%p)\n", |
258 | (void *)rela->r_offset, | | 258 | (void *)rela->r_offset, |
259 | (void *)where, | | 259 | (void *)where, |
260 | (void *)rela->r_addend, | | 260 | (void *)rela->r_addend, |
261 | (void *)*((Elf_Addr *)where) )); | | 261 | (void *)*((Elf_Addr *)where) )); |
262 | } else { | | 262 | } else { |
263 | sym = symtab + symnum; | | 263 | sym = symtab + symnum; |
264 | | | 264 | |
265 | hdbg(("PLABEL32 rela @%p(%p), symnum=%ld(%p) -> %p(%p)\n", | | 265 | hdbg(("PLABEL32 rela @%p(%p), symnum=%ld(%p) -> %p(%p)\n", |
266 | (void *)rela->r_offset, | | 266 | (void *)rela->r_offset, |
267 | (void *)where, | | 267 | (void *)where, |
268 | symnum, | | 268 | symnum, |
269 | (void *)sym->st_value, | | 269 | (void *)sym->st_value, |
270 | (void *)rela->r_addend, | | 270 | (void *)rela->r_addend, |
271 | (void *)*((Elf_Addr *)where) )); | | 271 | (void *)*((Elf_Addr *)where) )); |
272 | } | | 272 | } |
273 | break; | | 273 | break; |
274 | default: | | 274 | default: |
275 | hdbg(("rela XXX reloc\n")); | | 275 | hdbg(("rela XXX reloc\n")); |
276 | break; | | 276 | break; |
277 | } | | 277 | } |
278 | } | | 278 | } |
279 | #endif /* RTLD_DEBUG_HPPA */ | | 279 | #endif /* RTLD_DEBUG_HPPA */ |
280 | } | | 280 | } |
281 | | | 281 | |
282 | /* | | 282 | /* |
283 | * This allocates a PLABEL. If called with a non-NULL def, the | | 283 | * This allocates a PLABEL. If called with a non-NULL def, the |
284 | * plabel is for the function associated with that definition | | 284 | * plabel is for the function associated with that definition |
285 | * in the defining object defobj, plus the given addend. If | | 285 | * in the defining object defobj, plus the given addend. If |
286 | * called with a NULL def, the plabel is for the function at | | 286 | * called with a NULL def, the plabel is for the function at |
287 | * the (unrelocated) address in addend in the object defobj. | | 287 | * the (unrelocated) address in addend in the object defobj. |
288 | */ | | 288 | */ |
289 | Elf_Addr | | 289 | Elf_Addr |
290 | _rtld_function_descriptor_alloc(const Obj_Entry *defobj, const Elf_Sym *def, | | 290 | _rtld_function_descriptor_alloc(const Obj_Entry *defobj, const Elf_Sym *def, |
291 | Elf_Addr addend) | | 291 | Elf_Addr addend) |
292 | { | | 292 | { |
293 | Elf_Addr func_pc, func_sl; | | 293 | Elf_Addr func_pc, func_sl; |
294 | hppa_plabel *plabel; | | 294 | hppa_plabel *plabel; |
295 | | | 295 | |
296 | if (def != NULL) { | | 296 | if (def != NULL) { |
297 | | | 297 | |
298 | /* | | 298 | /* |
299 | * We assume that symbols of type STT_NOTYPE | | 299 | * We assume that symbols of type STT_NOTYPE |
300 | * are undefined. Return NULL for these. | | 300 | * are undefined. Return NULL for these. |
301 | */ | | 301 | */ |
302 | if (ELF_ST_TYPE(def->st_info) == STT_NOTYPE) | | 302 | if (ELF_ST_TYPE(def->st_info) == STT_NOTYPE) |
303 | return (Elf_Addr)NULL; | | 303 | return (Elf_Addr)NULL; |
304 | | | 304 | |
305 | /* Otherwise assert that this symbol must be a function. */ | | 305 | /* Otherwise assert that this symbol must be a function. */ |
306 | assert(ELF_ST_TYPE(def->st_info) == STT_FUNC); | | 306 | assert(ELF_ST_TYPE(def->st_info) == STT_FUNC); |
307 | | | 307 | |
308 | func_pc = (Elf_Addr)(defobj->relocbase + def->st_value + | | 308 | func_pc = (Elf_Addr)(defobj->relocbase + def->st_value + |
309 | addend); | | 309 | addend); |
310 | } else | | 310 | } else |
311 | func_pc = (Elf_Addr)(defobj->relocbase + addend); | | 311 | func_pc = (Elf_Addr)(defobj->relocbase + addend); |
312 | | | 312 | |
313 | /* | | 313 | /* |
314 | * Search the existing PLABELs for one matching | | 314 | * Search the existing PLABELs for one matching |
315 | * this function. If there is one, return it. | | 315 | * this function. If there is one, return it. |
316 | */ | | 316 | */ |
317 | func_sl = (Elf_Addr)(defobj->pltgot); | | 317 | func_sl = (Elf_Addr)(defobj->pltgot); |
318 | SLIST_FOREACH(plabel, &hppa_plabel_list, hppa_plabel_next) | | 318 | SLIST_FOREACH(plabel, &hppa_plabel_list, hppa_plabel_next) |
319 | if (plabel->hppa_plabel_pc == func_pc && | | 319 | if (plabel->hppa_plabel_pc == func_pc && |
320 | plabel->hppa_plabel_sl == func_sl) | | 320 | plabel->hppa_plabel_sl == func_sl) |
321 | return RTLD_MAKE_PLABEL(plabel); | | 321 | return RTLD_MAKE_PLABEL(plabel); |
322 | | | 322 | |
323 | /* | | 323 | /* |
324 | * Once we've used up the preallocated set, we start | | 324 | * Once we've used up the preallocated set, we start |
325 | * using NEW to allocate plabels. | | 325 | * using NEW to allocate plabels. |
326 | */ | | 326 | */ |
327 | if (hppa_plabel_pre_next < HPPA_PLABEL_PRE) | | 327 | if (hppa_plabel_pre_next < HPPA_PLABEL_PRE) |
328 | plabel = &hppa_plabel_pre[hppa_plabel_pre_next++]; | | 328 | plabel = &hppa_plabel_pre[hppa_plabel_pre_next++]; |
329 | else { | | 329 | else { |
330 | plabel = NEW(hppa_plabel); | | 330 | plabel = NEW(hppa_plabel); |
331 | if (plabel == NULL) | | 331 | if (plabel == NULL) |
332 | return (Elf_Addr)-1; | | 332 | return (Elf_Addr)-1; |
333 | } | | 333 | } |
334 | | | 334 | |
335 | /* Fill the new entry and insert it on the list. */ | | 335 | /* Fill the new entry and insert it on the list. */ |
336 | plabel->hppa_plabel_pc = func_pc; | | 336 | plabel->hppa_plabel_pc = func_pc; |
337 | plabel->hppa_plabel_sl = func_sl; | | 337 | plabel->hppa_plabel_sl = func_sl; |
338 | SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next); | | 338 | SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next); |
339 | | | 339 | |
340 | return RTLD_MAKE_PLABEL(plabel); | | 340 | return RTLD_MAKE_PLABEL(plabel); |
341 | } | | 341 | } |
342 | | | 342 | |
343 | /* | | 343 | /* |
344 | * If a pointer is a PLABEL, this unwraps it. | | 344 | * If a pointer is a PLABEL, this unwraps it. |
345 | */ | | 345 | */ |
346 | const void * | | 346 | const void * |
347 | _rtld_function_descriptor_function(const void *addr) | | 347 | _rtld_function_descriptor_function(const void *addr) |
348 | { | | 348 | { |
349 | return (RTLD_IS_PLABEL(addr) ? | | 349 | return (RTLD_IS_PLABEL(addr) ? |
350 | (const void *) RTLD_GET_PLABEL(addr)->hppa_plabel_pc : | | 350 | (const void *) RTLD_GET_PLABEL(addr)->hppa_plabel_pc : |
351 | addr); | | 351 | addr); |
352 | } | | 352 | } |
353 | | | 353 | |
354 | /* This sets up an object's GOT. */ | | 354 | /* This sets up an object's GOT. */ |
355 | void | | 355 | void |
356 | _rtld_setup_pltgot(const Obj_Entry *obj) | | 356 | _rtld_setup_pltgot(const Obj_Entry *obj) |
357 | { | | 357 | { |
358 | __rtld_setup_hppa_pltgot(obj, obj->pltgot); | | 358 | __rtld_setup_hppa_pltgot(obj, obj->pltgot); |
359 | } | | 359 | } |
360 | | | 360 | |
361 | int | | 361 | int |
362 | _rtld_relocate_nonplt_objects(Obj_Entry *obj) | | 362 | _rtld_relocate_nonplt_objects(Obj_Entry *obj) |
363 | { | | 363 | { |
364 | const Elf_Rela *rela; | | 364 | const Elf_Rela *rela; |
365 | | | 365 | |
366 | for (rela = obj->rela; rela < obj->relalim; rela++) { | | 366 | for (rela = obj->rela; rela < obj->relalim; rela++) { |
367 | Elf_Addr *where; | | 367 | Elf_Addr *where; |
368 | const Elf_Sym *def; | | 368 | const Elf_Sym *def; |
369 | const Obj_Entry *defobj; | | 369 | const Obj_Entry *defobj; |
370 | Elf_Addr tmp; | | 370 | Elf_Addr tmp; |
371 | unsigned long symnum; | | 371 | unsigned long symnum; |
372 | | | 372 | |
373 | where = (Elf_Addr *)(obj->relocbase + rela->r_offset); | | 373 | where = (Elf_Addr *)(obj->relocbase + rela->r_offset); |
374 | symnum = ELF_R_SYM(rela->r_info); | | 374 | symnum = ELF_R_SYM(rela->r_info); |
375 | | | 375 | |
376 | switch (ELF_R_TYPE(rela->r_info)) { | | 376 | switch (ELF_R_TYPE(rela->r_info)) { |
377 | case R_TYPE(NONE): | | 377 | case R_TYPE(NONE): |
378 | break; | | 378 | break; |
379 | | | 379 | |
380 | case R_TYPE(DIR32): | | 380 | case R_TYPE(DIR32): |
381 | if (symnum) { | | 381 | if (symnum) { |
382 | /* | | 382 | /* |
383 | * This is either a DIR32 against a symbol | | 383 | * This is either a DIR32 against a symbol |
384 | * (def->st_name != 0), or against a local | | 384 | * (def->st_name != 0), or against a local |
385 | * section (def->st_name == 0). | | 385 | * section (def->st_name == 0). |
386 | */ | | 386 | */ |
387 | def = obj->symtab + symnum; | | 387 | def = obj->symtab + symnum; |
388 | defobj = obj; | | 388 | defobj = obj; |
389 | if (def->st_name != 0) | | 389 | if (def->st_name != 0) |
390 | def = _rtld_find_symdef(symnum, obj, | | 390 | def = _rtld_find_symdef(symnum, obj, |
391 | &defobj, false); | | 391 | &defobj, false); |
392 | if (def == NULL) | | 392 | if (def == NULL) |
393 | return -1; | | 393 | return -1; |
394 | | | 394 | |
395 | tmp = (Elf_Addr)(defobj->relocbase + | | 395 | tmp = (Elf_Addr)(defobj->relocbase + |
396 | def->st_value + rela->r_addend); | | 396 | def->st_value + rela->r_addend); |
397 | | | 397 | |
398 | if (load_ptr(where) != tmp) | | 398 | if (load_ptr(where) != tmp) |
399 | store_ptr(where, tmp); | | 399 | store_ptr(where, tmp); |
400 | rdbg(("DIR32 %s in %s --> %p in %s", | | 400 | rdbg(("DIR32 %s in %s --> %p in %s", |
401 | obj->strtab + obj->symtab[symnum].st_name, | | 401 | obj->strtab + obj->symtab[symnum].st_name, |
402 | obj->path, (void *)load_ptr(where), | | 402 | obj->path, (void *)load_ptr(where), |
403 | defobj->path)); | | 403 | defobj->path)); |
404 | } else { | | 404 | } else { |
405 | tmp = (Elf_Addr)(obj->relocbase + | | 405 | tmp = (Elf_Addr)(obj->relocbase + |
406 | rela->r_addend); | | 406 | rela->r_addend); |
407 | | | 407 | |
408 | if (load_ptr(where) != tmp) | | 408 | if (load_ptr(where) != tmp) |
409 | store_ptr(where, tmp); | | 409 | store_ptr(where, tmp); |
410 | rdbg(("DIR32 in %s --> %p", obj->path, | | 410 | rdbg(("DIR32 in %s --> %p", obj->path, |
411 | (void *)load_ptr(where))); | | 411 | (void *)load_ptr(where))); |
412 | } | | 412 | } |
413 | break; | | 413 | break; |
414 | | | 414 | |
415 | case R_TYPE(PLABEL32): | | 415 | case R_TYPE(PLABEL32): |
416 | if (symnum) { | | 416 | if (symnum) { |
417 | def = _rtld_find_symdef(symnum, obj, &defobj, | | 417 | def = _rtld_find_symdef(symnum, obj, &defobj, |
418 | false); | | 418 | false); |
419 | if (def == NULL) | | 419 | if (def == NULL) |
420 | return -1; | | 420 | return -1; |
421 | | | 421 | |
422 | tmp = _rtld_function_descriptor_alloc(defobj, | | 422 | tmp = _rtld_function_descriptor_alloc(defobj, |
423 | def, rela->r_addend); | | 423 | def, rela->r_addend); |
424 | if (tmp == (Elf_Addr)-1) | | 424 | if (tmp == (Elf_Addr)-1) |
425 | return -1; | | 425 | return -1; |
426 | | | 426 | |
427 | if (*where != tmp) | | 427 | if (*where != tmp) |
428 | *where = tmp; | | 428 | *where = tmp; |
429 | rdbg(("PLABEL32 %s in %s --> %p in %s", | | 429 | rdbg(("PLABEL32 %s in %s --> %p in %s", |
430 | obj->strtab + obj->symtab[symnum].st_name, | | 430 | obj->strtab + obj->symtab[symnum].st_name, |
431 | obj->path, (void *)*where, defobj->path)); | | 431 | obj->path, (void *)*where, defobj->path)); |
432 | } else { | | 432 | } else { |
433 | /* | | 433 | /* |
434 | * This is a PLABEL for a static function, and | | 434 | * This is a PLABEL for a static function, and |
435 | * the dynamic linker has both allocated a PLT | | 435 | * the dynamic linker has both allocated a PLT |
436 | * entry for this function and told us where it | | 436 | * entry for this function and told us where it |
437 | * is. We can safely use the PLT entry as the | | 437 | * is. We can safely use the PLT entry as the |
438 | * PLABEL because there should be no other | | 438 | * PLABEL because there should be no other |
439 | * PLABEL reloc referencing this function. | | 439 | * PLABEL reloc referencing this function. |
440 | * This object should also have an IPLT | | 440 | * This object should also have an IPLT |
441 | * relocation to initialize the PLT entry. | | 441 | * relocation to initialize the PLT entry. |
442 | * | | 442 | * |
443 | * The dynamic linker should also have ensured | | 443 | * The dynamic linker should also have ensured |
444 | * that the addend has the | | 444 | * that the addend has the |
445 | * next-least-significant bit set; the | | 445 | * next-least-significant bit set; the |
446 | * $$dyncall millicode uses this to distinguish | | 446 | * $$dyncall millicode uses this to distinguish |
447 | * a PLABEL pointer from a plain function | | 447 | * a PLABEL pointer from a plain function |
448 | * pointer. | | 448 | * pointer. |
449 | */ | | 449 | */ |
450 | tmp = (Elf_Addr) | | 450 | tmp = (Elf_Addr) |
451 | (obj->relocbase + rela->r_addend); | | 451 | (obj->relocbase + rela->r_addend); |
452 | | | 452 | |
453 | if (*where != tmp) | | 453 | if (*where != tmp) |
454 | *where = tmp; | | 454 | *where = tmp; |
455 | rdbg(("PLABEL32 in %s --> %p", obj->path, | | 455 | rdbg(("PLABEL32 in %s --> %p", obj->path, |
456 | (void *)*where)); | | 456 | (void *)*where)); |
457 | } | | 457 | } |
458 | break; | | 458 | break; |
459 | | | 459 | |
460 | case R_TYPE(COPY): | | 460 | case R_TYPE(COPY): |
461 | /* | | 461 | /* |
462 | * These are deferred until all other relocations have | | 462 | * These are deferred until all other relocations have |
463 | * been done. All we do here is make sure that the | | 463 | * been done. All we do here is make sure that the |
464 | * COPY relocation is not in a shared library. They | | 464 | * COPY relocation is not in a shared library. They |
465 | * are allowed only in executable files. | | 465 | * are allowed only in executable files. |
466 | */ | | 466 | */ |
467 | if (obj->isdynamic) { | | 467 | if (obj->isdynamic) { |
468 | _rtld_error( | | 468 | _rtld_error( |
469 | "%s: Unexpected R_COPY relocation in shared library", | | 469 | "%s: Unexpected R_COPY relocation in shared library", |
470 | obj->path); | | 470 | obj->path); |
471 | return -1; | | 471 | return -1; |
472 | } | | 472 | } |
473 | rdbg(("COPY (avoid in main)")); | | 473 | rdbg(("COPY (avoid in main)")); |
474 | break; | | 474 | break; |
475 | | | 475 | |
476 | case R_TYPE(TLS_TPREL32): | | 476 | case R_TYPE(TLS_TPREL32): |
477 | def = _rtld_find_symdef(symnum, obj, &defobj, false); | | 477 | def = _rtld_find_symdef(symnum, obj, &defobj, false); |
478 | if (def == NULL) | | 478 | if (def == NULL) |
479 | return -1; | | 479 | return -1; |
480 | | | 480 | |
481 | if (!defobj->tls_done && _rtld_tls_offset_allocate(obj)) | | 481 | if (!defobj->tls_done && _rtld_tls_offset_allocate(obj)) |
482 | return -1; | | 482 | return -1; |
483 | | | 483 | |
484 | *where = (Elf_Addr)(obj->tlsoffset + def->st_value + | | 484 | *where = (Elf_Addr)(defobj->tlsoffset + def->st_value + |
485 | rela->r_addend + sizeof(struct tls_tcb)); | | 485 | rela->r_addend + sizeof(struct tls_tcb)); |
486 | | | 486 | |
487 | rdbg(("TPREL32 %s in %s --> %p in %s", | | 487 | rdbg(("TPREL32 %s in %s --> %p in %s", |
488 | obj->strtab + obj->symtab[symnum].st_name, | | 488 | obj->strtab + obj->symtab[symnum].st_name, |
489 | obj->path, (void *)*where, defobj->path)); | | 489 | obj->path, (void *)*where, defobj->path)); |
490 | break; | | 490 | break; |
491 | | | 491 | |
492 | case R_TYPE(TLS_DTPMOD32): | | 492 | case R_TYPE(TLS_DTPMOD32): |
493 | def = _rtld_find_symdef(symnum, obj, &defobj, false); | | 493 | def = _rtld_find_symdef(symnum, obj, &defobj, false); |
494 | if (def == NULL) | | 494 | if (def == NULL) |
495 | return -1; | | 495 | return -1; |
496 | | | 496 | |
497 | *where = (Elf_Addr)(defobj->tlsindex); | | 497 | *where = (Elf_Addr)(defobj->tlsindex); |
498 | | | 498 | |
499 | rdbg(("TLS_DTPMOD32 %s in %s --> %p", | | 499 | rdbg(("TLS_DTPMOD32 %s in %s --> %p", |
500 | obj->strtab + obj->symtab[symnum].st_name, | | 500 | obj->strtab + obj->symtab[symnum].st_name, |
501 | obj->path, (void *)*where)); | | 501 | obj->path, (void *)*where)); |
502 | | | 502 | |
503 | break; | | 503 | break; |
504 | | | 504 | |
505 | case R_TYPE(TLS_DTPOFF32): | | 505 | case R_TYPE(TLS_DTPOFF32): |
506 | def = _rtld_find_symdef(symnum, obj, &defobj, false); | | 506 | def = _rtld_find_symdef(symnum, obj, &defobj, false); |
507 | if (def == NULL) | | 507 | if (def == NULL) |
508 | return -1; | | 508 | return -1; |
509 | | | 509 | |
510 | *where = (Elf_Addr)(def->st_value); | | 510 | *where = (Elf_Addr)(def->st_value); |
511 | | | 511 | |
512 | rdbg(("TLS_DTPOFF32 %s in %s --> %p", | | 512 | rdbg(("TLS_DTPOFF32 %s in %s --> %p", |
513 | obj->strtab + obj->symtab[symnum].st_name, | | 513 | obj->strtab + obj->symtab[symnum].st_name, |
514 | obj->path, (void *)*where)); | | 514 | obj->path, (void *)*where)); |
515 | | | 515 | |
516 | break; | | 516 | break; |
517 | | | 517 | |
518 | default: | | 518 | default: |
519 | rdbg(("sym = %lu, type = %lu, offset = %p, " | | 519 | rdbg(("sym = %lu, type = %lu, offset = %p, " |
520 | "addend = %p, contents = %p, symbol = %s", | | 520 | "addend = %p, contents = %p, symbol = %s", |
521 | symnum, (u_long)ELF_R_TYPE(rela->r_info), | | 521 | symnum, (u_long)ELF_R_TYPE(rela->r_info), |
522 | (void *)rela->r_offset, (void *)rela->r_addend, | | 522 | (void *)rela->r_offset, (void *)rela->r_addend, |
523 | (void *)load_ptr(where), | | 523 | (void *)load_ptr(where), |
524 | obj->strtab + obj->symtab[symnum].st_name)); | | 524 | obj->strtab + obj->symtab[symnum].st_name)); |
525 | _rtld_error("%s: Unsupported relocation type %ld " | | 525 | _rtld_error("%s: Unsupported relocation type %ld " |
526 | "in non-PLT relocations", | | 526 | "in non-PLT relocations", |
527 | obj->path, (u_long) ELF_R_TYPE(rela->r_info)); | | 527 | obj->path, (u_long) ELF_R_TYPE(rela->r_info)); |
528 | return -1; | | 528 | return -1; |
529 | } | | 529 | } |
530 | } | | 530 | } |
531 | return 0; | | 531 | return 0; |
532 | } | | 532 | } |
533 | | | 533 | |
534 | int | | 534 | int |
535 | _rtld_relocate_plt_lazy(const Obj_Entry *obj) | | 535 | _rtld_relocate_plt_lazy(const Obj_Entry *obj) |
536 | { | | 536 | { |
537 | const Elf_Rela *rela; | | 537 | const Elf_Rela *rela; |
538 | | | 538 | |
539 | for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { | | 539 | for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { |
540 | Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); | | 540 | Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); |
541 | Elf_Addr func_pc, func_sl; | | 541 | Elf_Addr func_pc, func_sl; |
542 | | | 542 | |
543 | assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT)); | | 543 | assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT)); |
544 | | | 544 | |
545 | /* | | 545 | /* |
546 | * If this is an IPLT reloc for a static function, | | 546 | * If this is an IPLT reloc for a static function, |
547 | * fully resolve the PLT entry now. | | 547 | * fully resolve the PLT entry now. |
548 | */ | | 548 | */ |
549 | if (ELF_R_SYM(rela->r_info) == 0) { | | 549 | if (ELF_R_SYM(rela->r_info) == 0) { |
550 | func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend); | | 550 | func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend); |
551 | func_sl = (Elf_Addr)(obj->pltgot); | | 551 | func_sl = (Elf_Addr)(obj->pltgot); |
552 | } | | 552 | } |
553 | | | 553 | |
554 | /* | | 554 | /* |
555 | * Otherwise set up for lazy binding. | | 555 | * Otherwise set up for lazy binding. |
556 | */ | | 556 | */ |
557 | else { | | 557 | else { |
558 | /* | | 558 | /* |
559 | * This function pointer points to the PLT | | 559 | * This function pointer points to the PLT |
560 | * stub added by the linker, and instead of | | 560 | * stub added by the linker, and instead of |
561 | * a shared linkage value, we stash this | | 561 | * a shared linkage value, we stash this |
562 | * relocation's offset. The PLT stub has | | 562 | * relocation's offset. The PLT stub has |
563 | * already been set up to transfer to | | 563 | * already been set up to transfer to |
564 | * _rtld_bind_start. | | 564 | * _rtld_bind_start. |
565 | */ | | 565 | */ |
566 | func_pc = ((Elf_Addr)(obj->pltgot)) - 16; | | 566 | func_pc = ((Elf_Addr)(obj->pltgot)) - 16; |
567 | func_sl = (Elf_Addr) | | 567 | func_sl = (Elf_Addr) |
568 | ((const char *)rela - (const char *)(obj->pltrela)); | | 568 | ((const char *)rela - (const char *)(obj->pltrela)); |
569 | } | | 569 | } |
570 | rdbg(("lazy bind %s(%p) --> old=(%p,%p) new=(%p,%p)", | | 570 | rdbg(("lazy bind %s(%p) --> old=(%p,%p) new=(%p,%p)", |
571 | obj->path, | | 571 | obj->path, |
572 | (void *)where, | | 572 | (void *)where, |
573 | (void *)where[0], (void *)where[1], | | 573 | (void *)where[0], (void *)where[1], |
574 | (void *)func_pc, (void *)func_sl)); | | 574 | (void *)func_pc, (void *)func_sl)); |
575 | | | 575 | |
576 | /* | | 576 | /* |
577 | * Fill this PLT entry and return. | | 577 | * Fill this PLT entry and return. |
578 | */ | | 578 | */ |
579 | where[0] = func_pc; | | 579 | where[0] = func_pc; |
580 | where[1] = func_sl; | | 580 | where[1] = func_sl; |
581 | } | | 581 | } |
582 | return 0; | | 582 | return 0; |
583 | } | | 583 | } |
584 | | | 584 | |
585 | static inline int | | 585 | static inline int |
586 | _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, | | 586 | _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, |
587 | Elf_Addr *tp) | | 587 | Elf_Addr *tp) |
588 | { | | 588 | { |
589 | Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); | | 589 | Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); |
590 | const Elf_Sym *def; | | 590 | const Elf_Sym *def; |
591 | const Obj_Entry *defobj; | | 591 | const Obj_Entry *defobj; |
592 | Elf_Addr func_pc, func_sl; | | 592 | Elf_Addr func_pc, func_sl; |
593 | unsigned long info = rela->r_info; | | 593 | unsigned long info = rela->r_info; |
594 | | | 594 | |
595 | assert(ELF_R_TYPE(info) == R_TYPE(IPLT)); | | 595 | assert(ELF_R_TYPE(info) == R_TYPE(IPLT)); |
596 | | | 596 | |
597 | if (ELF_R_SYM(info) == 0) { | | 597 | if (ELF_R_SYM(info) == 0) { |
598 | func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend); | | 598 | func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend); |
599 | func_sl = (Elf_Addr)(obj->pltgot); | | 599 | func_sl = (Elf_Addr)(obj->pltgot); |
600 | } else { | | 600 | } else { |
601 | def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, | | 601 | def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, |
602 | tp != NULL); | | 602 | tp != NULL); |
603 | if (__predict_false(def == NULL)) | | 603 | if (__predict_false(def == NULL)) |
604 | return -1; | | 604 | return -1; |
605 | if (__predict_false(def == &_rtld_sym_zero)) | | 605 | if (__predict_false(def == &_rtld_sym_zero)) |
606 | return 0; | | 606 | return 0; |
607 | | | 607 | |
608 | func_pc = (Elf_Addr)(defobj->relocbase + def->st_value + | | 608 | func_pc = (Elf_Addr)(defobj->relocbase + def->st_value + |
609 | rela->r_addend); | | 609 | rela->r_addend); |
610 | func_sl = (Elf_Addr)(defobj->pltgot); | | 610 | func_sl = (Elf_Addr)(defobj->pltgot); |
611 | | | 611 | |
612 | rdbg(("bind now/fixup in %s --> old=(%p,%p) new=(%p,%p)", | | 612 | rdbg(("bind now/fixup in %s --> old=(%p,%p) new=(%p,%p)", |
613 | defobj->strtab + def->st_name, | | 613 | defobj->strtab + def->st_name, |
614 | (void *)where[0], (void *)where[1], | | 614 | (void *)where[0], (void *)where[1], |
615 | (void *)func_pc, (void *)func_sl)); | | 615 | (void *)func_pc, (void *)func_sl)); |
616 | } | | 616 | } |
617 | /* | | 617 | /* |
618 | * Fill this PLT entry and return. | | 618 | * Fill this PLT entry and return. |
619 | */ | | 619 | */ |
620 | if (where[0] != func_pc) | | 620 | if (where[0] != func_pc) |
621 | where[0] = func_pc; | | 621 | where[0] = func_pc; |
622 | if (where[1] != func_sl) | | 622 | if (where[1] != func_sl) |
623 | where[1] = func_sl; | | 623 | where[1] = func_sl; |
624 | | | 624 | |
625 | if (tp) | | 625 | if (tp) |
626 | *tp = (Elf_Addr)where; | | 626 | *tp = (Elf_Addr)where; |
627 | | | 627 | |
628 | return 0; | | 628 | return 0; |
629 | } | | 629 | } |
630 | | | 630 | |
631 | caddr_t | | 631 | caddr_t |
632 | _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) | | 632 | _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) |
633 | { | | 633 | { |
634 | const Elf_Rela *rela; | | 634 | const Elf_Rela *rela; |
635 | Elf_Addr new_value = 0; /* XXX gcc */ | | 635 | Elf_Addr new_value = 0; /* XXX gcc */ |
636 | int err; | | 636 | int err; |
637 | | | 637 | |
638 | rela = (const Elf_Rela *)((const char *)obj->pltrela + reloff); | | 638 | rela = (const Elf_Rela *)((const char *)obj->pltrela + reloff); |
639 | | | 639 | |
640 | assert(ELF_R_SYM(rela->r_info) != 0); | | 640 | assert(ELF_R_SYM(rela->r_info) != 0); |
641 | | | 641 | |
642 | _rtld_shared_enter(); | | 642 | _rtld_shared_enter(); |
643 | err = _rtld_relocate_plt_object(obj, rela, &new_value); | | 643 | err = _rtld_relocate_plt_object(obj, rela, &new_value); |
644 | if (err) | | 644 | if (err) |
645 | _rtld_die(); | | 645 | _rtld_die(); |
646 | _rtld_shared_exit(); | | 646 | _rtld_shared_exit(); |
647 | | | 647 | |
648 | return (caddr_t)new_value; | | 648 | return (caddr_t)new_value; |
649 | } | | 649 | } |
650 | | | 650 | |
651 | int | | 651 | int |
652 | _rtld_relocate_plt_objects(const Obj_Entry *obj) | | 652 | _rtld_relocate_plt_objects(const Obj_Entry *obj) |
653 | { | | 653 | { |
654 | const Elf_Rela *rela = obj->pltrela; | | 654 | const Elf_Rela *rela = obj->pltrela; |
655 | | | 655 | |
656 | for (; rela < obj->pltrelalim; rela++) { | | 656 | for (; rela < obj->pltrelalim; rela++) { |
657 | if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) | | 657 | if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) |
658 | return -1; | | 658 | return -1; |
659 | } | | 659 | } |
660 | return 0; | | 660 | return 0; |
661 | } | | 661 | } |