]>
Commit | Line | Data |
---|---|---|
d66e34cd | 1 | /* _dl_map_object -- Map in a shared object's segments from the file. |
c4b72918 | 2 | Copyright (C) 1995, 1996 Free Software Foundation, Inc. |
d66e34cd RM |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with the GNU C Library; see the file COPYING.LIB. If | |
17 | not, write to the Free Software Foundation, Inc., 675 Mass Ave, | |
18 | Cambridge, MA 02139, USA. */ | |
19 | ||
20 | #include <link.h> | |
21 | #include <sys/types.h> | |
22 | #include <sys/mman.h> | |
23 | #include <string.h> | |
24 | #include <fcntl.h> | |
25 | #include <unistd.h> | |
26 | #include <stdlib.h> | |
27 | #include <errno.h> | |
28 | #include "dynamic-link.h" | |
29 | ||
30 | ||
9b8a44cd RM |
31 | /* On some systems, no flag bits are given to specify file mapping. */ |
32 | #ifndef MAP_FILE | |
33 | #define MAP_FILE 0 | |
34 | #endif | |
35 | ||
36 | /* The right way to map in the shared library files is MAP_COPY, which | |
37 | makes a virtual copy of the data at the time of the mmap call; this | |
38 | guarantees the mapped pages will be consistent even if the file is | |
39 | overwritten. Some losing VM systems like Linux's lack MAP_COPY. All we | |
40 | get is MAP_PRIVATE, which copies each page when it is modified; this | |
41 | means if the file is overwritten, we may at some point get some pages | |
42 | from the new version after starting with pages from the old version. */ | |
43 | #ifndef MAP_COPY | |
44 | #define MAP_COPY MAP_PRIVATE | |
45 | #endif | |
46 | ||
47 | ||
d66e34cd RM |
48 | #include <endian.h> |
49 | #if BYTE_ORDER == BIG_ENDIAN | |
50 | #define byteorder ELFDATA2MSB | |
51 | #define byteorder_name "big-endian" | |
52 | #elif BYTE_ORDER == LITTLE_ENDIAN | |
53 | #define byteorder ELFDATA2LSB | |
54 | #define byteorder_name "little-endian" | |
55 | #else | |
56 | #error "Unknown BYTE_ORDER " BYTE_ORDER | |
57 | #define byteorder ELFDATANONE | |
58 | #endif | |
59 | ||
60 | #define STRING(x) #x | |
61 | ||
2064087b RM |
62 | #ifdef MAP_ANON |
63 | /* The fd is not examined when using MAP_ANON. */ | |
64 | #define ANONFD -1 | |
65 | #else | |
d66e34cd | 66 | int _dl_zerofd = -1; |
2064087b RM |
67 | #define ANONFD _dl_zerofd |
68 | #endif | |
69 | ||
266180eb | 70 | size_t _dl_pagesize; |
d66e34cd RM |
71 | |
72 | ||
706074a5 UD |
73 | /* Local version of `strdup' function. */ |
74 | static inline char * | |
75 | local_strdup (const char *s) | |
76 | { | |
77 | size_t len = strlen (s) + 1; | |
78 | void *new = malloc (len); | |
79 | ||
80 | if (new == NULL) | |
81 | return NULL; | |
82 | ||
83 | return (char *) memcpy (new, s, len); | |
84 | } | |
85 | ||
86 | ||
ea03559a RM |
87 | /* Map in the shared object NAME, actually located in REALNAME, and already |
88 | opened on FD. */ | |
89 | ||
90 | struct link_map * | |
706074a5 | 91 | _dl_map_object_from_fd (char *name, int fd, char *realname, |
ba79d61b | 92 | struct link_map *loader, int l_type) |
ea03559a | 93 | { |
622586fb | 94 | struct link_map *l = NULL; |
ea03559a RM |
95 | void *file_mapping = NULL; |
96 | size_t mapping_size = 0; | |
97 | ||
b122c703 | 98 | #define LOSE(s) lose (0, (s)) |
ea03559a RM |
99 | void lose (int code, const char *msg) |
100 | { | |
266180eb | 101 | (void) __close (fd); |
ea03559a | 102 | if (file_mapping) |
266180eb | 103 | __munmap (file_mapping, mapping_size); |
ba79d61b RM |
104 | if (l) |
105 | { | |
106 | /* Remove the stillborn object from the list and free it. */ | |
107 | if (l->l_prev) | |
108 | l->l_prev->l_next = l->l_next; | |
109 | if (l->l_next) | |
110 | l->l_next->l_prev = l->l_prev; | |
111 | free (l); | |
112 | } | |
706074a5 | 113 | free (name); |
ba79d61b RM |
114 | free (realname); |
115 | _dl_signal_error (code, name, msg); | |
ea03559a RM |
116 | } |
117 | ||
266180eb | 118 | inline caddr_t map_segment (ElfW(Addr) mapstart, size_t len, |
b122c703 RM |
119 | int prot, int fixed, off_t offset) |
120 | { | |
266180eb RM |
121 | caddr_t mapat = __mmap ((caddr_t) mapstart, len, prot, |
122 | fixed|MAP_COPY|MAP_FILE, | |
123 | fd, offset); | |
b122c703 RM |
124 | if (mapat == (caddr_t) -1) |
125 | lose (errno, "failed to map segment from shared object"); | |
126 | return mapat; | |
127 | } | |
128 | ||
ea03559a RM |
129 | /* Make sure LOCATION is mapped in. */ |
130 | void *map (off_t location, size_t size) | |
131 | { | |
132 | if ((off_t) mapping_size <= location + (off_t) size) | |
133 | { | |
134 | void *result; | |
135 | if (file_mapping) | |
266180eb RM |
136 | __munmap (file_mapping, mapping_size); |
137 | mapping_size = (location + size + 1 + _dl_pagesize - 1); | |
138 | mapping_size &= ~(_dl_pagesize - 1); | |
139 | result = __mmap (file_mapping, mapping_size, PROT_READ, | |
140 | MAP_COPY|MAP_FILE, fd, 0); | |
ea03559a RM |
141 | if (result == (void *) -1) |
142 | lose (errno, "cannot map file data"); | |
143 | file_mapping = result; | |
144 | } | |
145 | return file_mapping + location; | |
146 | } | |
147 | ||
266180eb RM |
148 | const ElfW(Ehdr) *header; |
149 | const ElfW(Phdr) *phdr; | |
150 | const ElfW(Phdr) *ph; | |
b122c703 | 151 | int type; |
d66e34cd RM |
152 | |
153 | /* Look again to see if the real name matched another already loaded. */ | |
154 | for (l = _dl_loaded; l; l = l->l_next) | |
155 | if (! strcmp (realname, l->l_name)) | |
156 | { | |
157 | /* The object is already loaded. | |
158 | Just bump its reference count and return it. */ | |
266180eb | 159 | __close (fd); |
706074a5 | 160 | free (name); |
ea03559a | 161 | free (realname); |
d66e34cd RM |
162 | ++l->l_opencount; |
163 | return l; | |
164 | } | |
165 | ||
266180eb RM |
166 | if (_dl_pagesize == 0) |
167 | _dl_pagesize = __getpagesize (); | |
168 | ||
d66e34cd RM |
169 | /* Map in the first page to read the header. */ |
170 | header = map (0, sizeof *header); | |
d66e34cd | 171 | |
d66e34cd | 172 | /* Check the header for basic validity. */ |
c4b72918 RM |
173 | if (*(Elf32_Word *) &header->e_ident != |
174 | #if BYTE_ORDER == LITTLE_ENDIAN | |
175 | ((ELFMAG0 << (EI_MAG0 * 8)) | | |
176 | (ELFMAG1 << (EI_MAG1 * 8)) | | |
177 | (ELFMAG2 << (EI_MAG2 * 8)) | | |
178 | (ELFMAG3 << (EI_MAG3 * 8))) | |
179 | #else | |
180 | ((ELFMAG0 << (EI_MAG3 * 8)) | | |
181 | (ELFMAG1 << (EI_MAG2 * 8)) | | |
182 | (ELFMAG2 << (EI_MAG1 * 8)) | | |
183 | (ELFMAG3 << (EI_MAG0 * 8))) | |
184 | #endif | |
185 | ) | |
d66e34cd | 186 | LOSE ("invalid ELF header"); |
266180eb RM |
187 | #define ELF32_CLASS ELFCLASS32 |
188 | #define ELF64_CLASS ELFCLASS64 | |
189 | if (header->e_ident[EI_CLASS] != ELFW(CLASS)) | |
190 | LOSE ("ELF file class not " STRING(__ELF_WORDSIZE) "-bit"); | |
d66e34cd RM |
191 | if (header->e_ident[EI_DATA] != byteorder) |
192 | LOSE ("ELF file data encoding not " byteorder_name); | |
193 | if (header->e_ident[EI_VERSION] != EV_CURRENT) | |
194 | LOSE ("ELF file version ident not " STRING(EV_CURRENT)); | |
195 | if (header->e_version != EV_CURRENT) | |
196 | LOSE ("ELF file version not " STRING(EV_CURRENT)); | |
197 | if (! elf_machine_matches_host (header->e_machine)) | |
198 | LOSE ("ELF file machine architecture not " ELF_MACHINE_NAME); | |
266180eb | 199 | if (header->e_phentsize != sizeof (ElfW(Phdr))) |
d66e34cd RM |
200 | LOSE ("ELF file's phentsize not the expected size"); |
201 | ||
2064087b RM |
202 | #ifndef MAP_ANON |
203 | #define MAP_ANON 0 | |
d66e34cd RM |
204 | if (_dl_zerofd == -1) |
205 | { | |
206 | _dl_zerofd = _dl_sysdep_open_zero_fill (); | |
207 | if (_dl_zerofd == -1) | |
ba79d61b RM |
208 | { |
209 | __close (fd); | |
210 | _dl_signal_error (errno, NULL, "cannot open zero fill device"); | |
211 | } | |
d66e34cd | 212 | } |
2064087b | 213 | #endif |
d66e34cd | 214 | |
ba79d61b RM |
215 | /* Enter the new object in the list of loaded objects. */ |
216 | l = _dl_new_object (realname, name, l_type); | |
217 | if (! l) | |
218 | lose (ENOMEM, "cannot create shared object descriptor"); | |
219 | l->l_opencount = 1; | |
220 | l->l_loader = loader; | |
221 | ||
b122c703 RM |
222 | /* Extract the remaining details we need from the ELF header |
223 | and then map in the program header table. */ | |
224 | l->l_entry = header->e_entry; | |
225 | type = header->e_type; | |
226 | l->l_phnum = header->e_phnum; | |
266180eb | 227 | phdr = map (header->e_phoff, l->l_phnum * sizeof (ElfW(Phdr))); |
879bf2e6 | 228 | |
b122c703 RM |
229 | { |
230 | /* Scan the program header table, collecting its load commands. */ | |
231 | struct loadcmd | |
232 | { | |
266180eb | 233 | ElfW(Addr) mapstart, mapend, dataend, allocend; |
b122c703 RM |
234 | off_t mapoff; |
235 | int prot; | |
236 | } loadcmds[l->l_phnum], *c; | |
237 | size_t nloadcmds = 0; | |
d66e34cd | 238 | |
d66e34cd | 239 | l->l_ld = 0; |
b122c703 RM |
240 | l->l_phdr = 0; |
241 | l->l_addr = 0; | |
d66e34cd RM |
242 | for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph) |
243 | switch (ph->p_type) | |
244 | { | |
245 | /* These entries tell us where to find things once the file's | |
246 | segments are mapped in. We record the addresses it says | |
247 | verbatim, and later correct for the run-time load address. */ | |
248 | case PT_DYNAMIC: | |
249 | l->l_ld = (void *) ph->p_vaddr; | |
250 | break; | |
251 | case PT_PHDR: | |
252 | l->l_phdr = (void *) ph->p_vaddr; | |
253 | break; | |
254 | ||
255 | case PT_LOAD: | |
b122c703 RM |
256 | /* A load command tells us to map in part of the file. |
257 | We record the load commands and process them all later. */ | |
266180eb | 258 | if (ph->p_align % _dl_pagesize != 0) |
d66e34cd RM |
259 | LOSE ("ELF load command alignment not page-aligned"); |
260 | if ((ph->p_vaddr - ph->p_offset) % ph->p_align) | |
261 | LOSE ("ELF load command address/offset not properly aligned"); | |
262 | { | |
b122c703 RM |
263 | struct loadcmd *c = &loadcmds[nloadcmds++]; |
264 | c->mapstart = ph->p_vaddr & ~(ph->p_align - 1); | |
266180eb RM |
265 | c->mapend = ((ph->p_vaddr + ph->p_filesz + _dl_pagesize - 1) |
266 | & ~(_dl_pagesize - 1)); | |
b122c703 RM |
267 | c->dataend = ph->p_vaddr + ph->p_filesz; |
268 | c->allocend = ph->p_vaddr + ph->p_memsz; | |
269 | c->mapoff = ph->p_offset & ~(ph->p_align - 1); | |
270 | c->prot = 0; | |
d66e34cd | 271 | if (ph->p_flags & PF_R) |
b122c703 | 272 | c->prot |= PROT_READ; |
d66e34cd | 273 | if (ph->p_flags & PF_W) |
b122c703 | 274 | c->prot |= PROT_WRITE; |
d66e34cd | 275 | if (ph->p_flags & PF_X) |
b122c703 RM |
276 | c->prot |= PROT_EXEC; |
277 | break; | |
278 | } | |
279 | } | |
d66e34cd | 280 | |
b122c703 | 281 | /* We are done reading the file's headers now. Unmap them. */ |
266180eb | 282 | __munmap (file_mapping, mapping_size); |
b122c703 RM |
283 | |
284 | /* Now process the load commands and map segments into memory. */ | |
285 | c = loadcmds; | |
286 | ||
287 | if (type == ET_DYN || type == ET_REL) | |
288 | { | |
289 | /* This is a position-independent shared object. We can let the | |
290 | kernel map it anywhere it likes, but we must have space for all | |
291 | the segments in their specified positions relative to the first. | |
292 | So we map the first segment without MAP_FIXED, but with its | |
22930c9b RM |
293 | extent increased to cover all the segments. Then we remove |
294 | access from excess portion, and there is known sufficient space | |
295 | there to remap from the later segments. */ | |
b122c703 RM |
296 | caddr_t mapat; |
297 | mapat = map_segment (c->mapstart, | |
298 | loadcmds[nloadcmds - 1].allocend - c->mapstart, | |
299 | c->prot, 0, c->mapoff); | |
266180eb | 300 | l->l_addr = (ElfW(Addr)) mapat - c->mapstart; |
b122c703 | 301 | |
22930c9b RM |
302 | /* Change protection on the excess portion to disallow all access; |
303 | the portions we do not remap later will be inaccessible as if | |
304 | unallocated. Then jump into the normal segment-mapping loop to | |
305 | handle the portion of the segment past the end of the file | |
306 | mapping. */ | |
0d3726c3 | 307 | __mprotect ((caddr_t) (l->l_addr + c->mapend), |
266180eb RM |
308 | loadcmds[nloadcmds - 1].allocend - c->mapend, |
309 | 0); | |
b122c703 RM |
310 | goto postmap; |
311 | } | |
312 | ||
313 | while (c < &loadcmds[nloadcmds]) | |
314 | { | |
315 | if (c->mapend > c->mapstart) | |
316 | /* Map the segment contents from the file. */ | |
317 | map_segment (l->l_addr + c->mapstart, c->mapend - c->mapstart, | |
318 | c->prot, MAP_FIXED, c->mapoff); | |
319 | ||
320 | postmap: | |
321 | if (c->allocend > c->dataend) | |
322 | { | |
323 | /* Extra zero pages should appear at the end of this segment, | |
324 | after the data mapped from the file. */ | |
266180eb | 325 | ElfW(Addr) zero, zeroend, zeropage; |
b122c703 RM |
326 | |
327 | zero = l->l_addr + c->dataend; | |
328 | zeroend = l->l_addr + c->allocend; | |
266180eb | 329 | zeropage = (zero + _dl_pagesize - 1) & ~(_dl_pagesize - 1); |
d66e34cd | 330 | |
b122c703 RM |
331 | if (zeroend < zeropage) |
332 | /* All the extra data is in the last page of the segment. | |
333 | We can just zero it. */ | |
334 | zeropage = zeroend; | |
335 | ||
336 | if (zeropage > zero) | |
d66e34cd | 337 | { |
b122c703 RM |
338 | /* Zero the final part of the last page of the segment. */ |
339 | if ((c->prot & PROT_WRITE) == 0) | |
d66e34cd | 340 | { |
b122c703 | 341 | /* Dag nab it. */ |
266180eb RM |
342 | if (__mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)), |
343 | _dl_pagesize, c->prot|PROT_WRITE) < 0) | |
b122c703 | 344 | lose (errno, "cannot change memory protections"); |
d66e34cd | 345 | } |
b122c703 RM |
346 | memset ((void *) zero, 0, zeropage - zero); |
347 | if ((c->prot & PROT_WRITE) == 0) | |
266180eb RM |
348 | __mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)), |
349 | _dl_pagesize, c->prot); | |
b122c703 | 350 | } |
d66e34cd | 351 | |
b122c703 RM |
352 | if (zeroend > zeropage) |
353 | { | |
354 | /* Map the remaining zero pages in from the zero fill FD. */ | |
355 | caddr_t mapat; | |
266180eb RM |
356 | mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage, |
357 | c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, | |
2064087b | 358 | ANONFD, 0); |
b122c703 | 359 | if (mapat == (caddr_t) -1) |
9b8a44cd | 360 | lose (errno, "cannot map zero-fill pages"); |
d66e34cd RM |
361 | } |
362 | } | |
d66e34cd | 363 | |
b122c703 | 364 | ++c; |
879bf2e6 | 365 | } |
0d3726c3 RM |
366 | |
367 | if (l->l_phdr == 0) | |
368 | { | |
369 | /* There was no PT_PHDR specified. We need to find the phdr in the | |
370 | load image ourselves. We assume it is in fact in the load image | |
371 | somewhere, and that the first load command starts at the | |
372 | beginning of the file and thus contains the ELF file header. */ | |
373 | ElfW(Addr) bof = l->l_addr + loadcmds[0].mapstart; | |
374 | assert (loadcmds[0].mapoff == 0); | |
375 | l->l_phdr = (void *) (bof + ((const ElfW(Ehdr) *) bof)->e_phoff); | |
376 | } | |
377 | else | |
378 | /* Adjust the PT_PHDR value by the runtime load address. */ | |
379 | (ElfW(Addr)) l->l_phdr += l->l_addr; | |
b122c703 | 380 | } |
d66e34cd | 381 | |
6d9756c9 RM |
382 | /* We are done mapping in the file. We no longer need the descriptor. */ |
383 | __close (fd); | |
384 | ||
ba79d61b RM |
385 | if (l->l_type == lt_library && type == ET_EXEC) |
386 | l->l_type = lt_executable; | |
9b8a44cd | 387 | |
b122c703 RM |
388 | if (l->l_ld == 0) |
389 | { | |
390 | if (type == ET_DYN) | |
391 | LOSE ("object file has no dynamic section"); | |
392 | } | |
393 | else | |
266180eb | 394 | (ElfW(Addr)) l->l_ld += l->l_addr; |
879bf2e6 | 395 | |
463e148b RM |
396 | l->l_entry += l->l_addr; |
397 | ||
d66e34cd RM |
398 | elf_get_dynamic_info (l->l_ld, l->l_info); |
399 | if (l->l_info[DT_HASH]) | |
400 | _dl_setup_hash (l); | |
401 | ||
402 | return l; | |
403 | } | |
ba79d61b RM |
404 | \f |
405 | /* Try to open NAME in one of the directories in DIRPATH. | |
406 | Return the fd, or -1. If successful, fill in *REALNAME | |
407 | with the malloc'd full directory name. */ | |
408 | ||
409 | static int | |
410 | open_path (const char *name, size_t namelen, | |
411 | const char *dirpath, | |
412 | char **realname) | |
413 | { | |
414 | char *buf; | |
415 | const char *p; | |
416 | int fd; | |
417 | ||
418 | p = dirpath; | |
419 | if (p == NULL || *p == '\0') | |
420 | { | |
421 | errno = ENOENT; | |
422 | return -1; | |
423 | } | |
424 | ||
425 | buf = __alloca (strlen (dirpath) + 1 + namelen); | |
426 | do | |
427 | { | |
428 | size_t buflen; | |
429 | ||
430 | dirpath = p; | |
431 | p = strpbrk (dirpath, ":;"); | |
432 | if (p == NULL) | |
433 | p = strchr (dirpath, '\0'); | |
434 | ||
435 | if (p == dirpath) | |
436 | { | |
437 | /* Two adjacent colons, or a colon at the beginning or the end of | |
438 | the path means to search the current directory. */ | |
439 | (void) memcpy (buf, name, namelen); | |
440 | buflen = namelen; | |
441 | } | |
442 | else | |
443 | { | |
444 | /* Construct the pathname to try. */ | |
445 | (void) memcpy (buf, dirpath, p - dirpath); | |
446 | buf[p - dirpath] = '/'; | |
447 | (void) memcpy (&buf[(p - dirpath) + 1], name, namelen); | |
448 | buflen = p - dirpath + 1 + namelen; | |
449 | } | |
450 | ||
451 | fd = __open (buf, O_RDONLY); | |
452 | if (fd != -1) | |
453 | { | |
454 | *realname = malloc (buflen); | |
455 | if (*realname) | |
456 | { | |
457 | memcpy (*realname, buf, buflen); | |
458 | return fd; | |
459 | } | |
460 | else | |
461 | { | |
462 | /* No memory for the name, we certainly won't be able | |
463 | to load and link it. */ | |
464 | __close (fd); | |
465 | return -1; | |
466 | } | |
467 | } | |
468 | if (errno != ENOENT && errno != EACCES) | |
469 | /* The file exists and is readable, but something went wrong. */ | |
470 | return -1; | |
471 | } | |
472 | while (*p++ != '\0'); | |
473 | ||
474 | return -1; | |
475 | } | |
476 | ||
477 | /* Map in the shared object file NAME. */ | |
478 | ||
479 | struct link_map * | |
480 | _dl_map_object (struct link_map *loader, const char *name, int type) | |
481 | { | |
482 | int fd; | |
483 | char *realname; | |
484 | struct link_map *l; | |
485 | ||
486 | /* Look for this name among those already loaded. */ | |
487 | for (l = _dl_loaded; l; l = l->l_next) | |
5f0e6fc7 | 488 | if (! strcmp (name, l->l_libname) || /* NAME was requested before. */ |
ffee1316 | 489 | ! strcmp (name, l->l_name) || /* NAME was found before. */ |
5f0e6fc7 RM |
490 | /* If the requested name matches the soname of a loaded object, |
491 | use that object. */ | |
492 | (l->l_info[DT_SONAME] && | |
3d3ac840 | 493 | ! strcmp (name, (const char *) (l->l_addr + |
ffee1316 RM |
494 | l->l_info[DT_STRTAB]->d_un.d_ptr + |
495 | l->l_info[DT_SONAME]->d_un.d_val)))) | |
ba79d61b RM |
496 | { |
497 | /* The object is already loaded. | |
498 | Just bump its reference count and return it. */ | |
499 | ++l->l_opencount; | |
500 | return l; | |
501 | } | |
502 | ||
503 | if (strchr (name, '/') == NULL) | |
504 | { | |
505 | /* Search for NAME in several places. */ | |
506 | ||
507 | size_t namelen = strlen (name) + 1; | |
508 | ||
509 | inline void trypath (const char *dirpath) | |
510 | { | |
511 | fd = open_path (name, namelen, dirpath, &realname); | |
512 | } | |
513 | ||
514 | fd = -1; | |
a23db8e4 RM |
515 | |
516 | /* First try the DT_RPATH of the dependent object that caused NAME | |
517 | to be loaded. Then that object's dependent, and on up. */ | |
518 | for (l = loader; fd == -1 && l; l = l->l_loader) | |
ba79d61b RM |
519 | if (l && l->l_info[DT_RPATH]) |
520 | trypath ((const char *) (l->l_addr + | |
521 | l->l_info[DT_STRTAB]->d_un.d_ptr + | |
522 | l->l_info[DT_RPATH]->d_un.d_val)); | |
a23db8e4 RM |
523 | /* If dynamically linked, try the DT_RPATH of the executable itself. */ |
524 | l = _dl_loaded; | |
f9496a7b | 525 | if (fd == -1 && l && l->l_type != lt_loaded && l->l_info[DT_RPATH]) |
a23db8e4 RM |
526 | trypath ((const char *) (l->l_addr + |
527 | l->l_info[DT_STRTAB]->d_un.d_ptr + | |
528 | l->l_info[DT_RPATH]->d_un.d_val)); | |
529 | /* Try an environment variable (unless setuid). */ | |
cddcfecf | 530 | if (fd == -1 && ! __libc_enable_secure) |
ba79d61b | 531 | trypath (getenv ("LD_LIBRARY_PATH")); |
f18edac3 RM |
532 | if (fd == -1) |
533 | { | |
534 | /* Check the list of libraries in the file /etc/ld.so.cache, | |
535 | for compatibility with Linux's ldconfig program. */ | |
536 | extern const char *_dl_load_cache_lookup (const char *name); | |
537 | const char *cached = _dl_load_cache_lookup (name); | |
538 | if (cached) | |
539 | { | |
540 | fd = __open (cached, O_RDONLY); | |
541 | if (fd != -1) | |
542 | { | |
706074a5 UD |
543 | realname = local_strdup (cached); |
544 | if (realname == NULL) | |
f18edac3 RM |
545 | { |
546 | __close (fd); | |
547 | fd = -1; | |
548 | } | |
549 | } | |
550 | } | |
551 | } | |
a23db8e4 | 552 | /* Finally, try the default path. */ |
ba79d61b RM |
553 | if (fd == -1) |
554 | { | |
555 | extern const char *_dl_rpath; /* Set in rtld.c. */ | |
556 | trypath (_dl_rpath); | |
557 | } | |
558 | } | |
559 | else | |
560 | { | |
561 | fd = __open (name, O_RDONLY); | |
562 | if (fd != -1) | |
563 | { | |
706074a5 UD |
564 | realname = local_strdup (name); |
565 | if (realname == NULL) | |
ba79d61b RM |
566 | { |
567 | __close (fd); | |
568 | fd = -1; | |
569 | } | |
570 | } | |
571 | } | |
572 | ||
706074a5 UD |
573 | if (fd != -1) |
574 | { | |
575 | name = local_strdup (name); | |
576 | if (name == NULL) | |
577 | { | |
578 | __close (fd); | |
579 | fd = -1; | |
580 | } | |
581 | } | |
582 | ||
ba79d61b RM |
583 | if (fd == -1) |
584 | _dl_signal_error (errno, name, "cannot open shared object file"); | |
585 | ||
586 | return _dl_map_object_from_fd (name, fd, realname, loader, type); | |
587 | } |