]> sourceware.org Git - glibc.git/blob - elf/dl-load.c
Tue May 30 15:52:32 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
[glibc.git] / elf / dl-load.c
1 /* _dl_map_object -- Map in a shared object's segments from the file.
2 Copyright (C) 1995 Free Software Foundation, Inc.
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
31 #include <endian.h>
32 #if BYTE_ORDER == BIG_ENDIAN
33 #define byteorder ELFDATA2MSB
34 #define byteorder_name "big-endian"
35 #elif BYTE_ORDER == LITTLE_ENDIAN
36 #define byteorder ELFDATA2LSB
37 #define byteorder_name "little-endian"
38 #else
39 #error "Unknown BYTE_ORDER " BYTE_ORDER
40 #define byteorder ELFDATANONE
41 #endif
42
43 #define STRING(x) #x
44
45 int _dl_zerofd = -1;
46
47
48 /* Try to open NAME in one of the directories in DIRPATH.
49 Return the fd, or -1. If successful, fill in *REALNAME
50 with the malloc'd full directory name. */
51
52 static int
53 open_path (const char *name, size_t namelen,
54 const char *dirpath,
55 char **realname)
56 {
57 char buf[strlen (dirpath) + 1 + namelen];
58 const char *p;
59 int fd;
60
61 p = dirpath;
62 if (p == NULL || *p == '\0')
63 {
64 errno = ENOENT;
65 return -1;
66 }
67
68 do
69 {
70 dirpath = p;
71 p = strpbrk (dirpath, ":;");
72 if (p == NULL)
73 p = strchr (dirpath, '\0');
74
75 if (p == dirpath)
76 /* Two adjacent colons, or a colon at the beginning or the end of
77 the path means to search the current directory. */
78 (void) memcpy (buf, name, namelen);
79 else
80 {
81 /* Construct the pathname to try. */
82 (void) memcpy (buf, dirpath, p - dirpath);
83 buf[p - dirpath] = '/';
84 (void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
85 }
86
87 fd = open (buf, O_RDONLY);
88 if (fd != -1)
89 {
90 *realname = strdup (buf);
91 return fd;
92 }
93 if (errno != ENOENT && errno != EACCES)
94 /* The file exists and is readable, but something went wrong. */
95 return -1;
96 }
97 while (*p++ != '\0');
98
99 return -1;
100 }
101
102
103 /* Map in the shared object file NAME. */
104
105 struct link_map *
106 _dl_map_object (struct link_map *loader, const char *name,
107 Elf32_Addr *entry_point)
108 {
109 int fd;
110 struct link_map *l = NULL;
111 char *realname;
112 const size_t pagesize = getpagesize ();
113 void *file_mapping = NULL;
114 size_t mapping_size = 0;
115
116 void lose (int code, const char *msg)
117 {
118 (void) close (fd);
119 if (file_mapping)
120 munmap (file_mapping, mapping_size);
121 _dl_signal_error (code, l ? l->l_name : name, msg);
122 }
123
124 /* Make sure LOCATION is mapped in. */
125 void *map (off_t location, size_t size)
126 {
127 if ((off_t) mapping_size <= location + (off_t) size)
128 {
129 void *result;
130 if (file_mapping)
131 munmap (file_mapping, mapping_size);
132 mapping_size = (location + size + 1 + pagesize - 1);
133 mapping_size &= ~(pagesize - 1);
134 result = mmap (file_mapping, mapping_size, PROT_READ,
135 MAP_COPY|MAP_FILE, fd, 0);
136 if (result == (void *) -1)
137 lose (errno, "cannot map file data");
138 file_mapping = result;
139 }
140 return file_mapping + location;
141 }
142
143 const Elf32_Ehdr *header;
144
145 /* Look for this name among those already loaded. */
146 for (l = _dl_loaded; l; l = l->l_next)
147 if (! strcmp (name, l->l_libname))
148 {
149 /* The object is already loaded.
150 Just bump its reference count and return it. */
151 ++l->l_opencount;
152 return l;
153 }
154
155 if (strchr (name, '/') == NULL)
156 {
157 /* Search for NAME in several places. */
158
159 size_t namelen = strlen (name) + 1;
160
161 inline void trypath (const char *dirpath)
162 {
163 fd = open_path (name, namelen, dirpath, &realname);
164 }
165
166 fd = -1;
167 if (loader && loader->l_info[DT_RPATH])
168 trypath ((const char *) (loader->l_addr +
169 loader->l_info[DT_RPATH]->d_un.d_ptr));
170 if (fd == -1 && ! _dl_secure)
171 trypath (getenv ("LD_LIBRARY_PATH"));
172 if (fd == -1)
173 trypath ("/lib:/usr/lib");
174 }
175 else
176 {
177 fd = open (name, O_RDONLY);
178 if (fd != -1)
179 realname = strdup (name);
180 }
181
182 if (fd == -1)
183 lose (errno, "cannot open shared object file");
184
185 /* Look again to see if the real name matched another already loaded. */
186 for (l = _dl_loaded; l; l = l->l_next)
187 if (! strcmp (realname, l->l_name))
188 {
189 /* The object is already loaded.
190 Just bump its reference count and return it. */
191 close (fd);
192 ++l->l_opencount;
193 return l;
194 }
195
196
197 /* Map in the first page to read the header. */
198 header = map (0, sizeof *header);
199
200 #undef LOSE
201 #define LOSE(s) lose (0, (s))
202 /* Check the header for basic validity. */
203 if (*(Elf32_Word *) &header->e_ident != ((ELFMAG0 << (EI_MAG0 * 8)) |
204 (ELFMAG1 << (EI_MAG1 * 8)) |
205 (ELFMAG2 << (EI_MAG2 * 8)) |
206 (ELFMAG3 << (EI_MAG3 * 8))))
207 LOSE ("invalid ELF header");
208 if (header->e_ident[EI_CLASS] != ELFCLASS32)
209 LOSE ("ELF file class not 32-bit");
210 if (header->e_ident[EI_DATA] != byteorder)
211 LOSE ("ELF file data encoding not " byteorder_name);
212 if (header->e_ident[EI_VERSION] != EV_CURRENT)
213 LOSE ("ELF file version ident not " STRING(EV_CURRENT));
214 if (header->e_version != EV_CURRENT)
215 LOSE ("ELF file version not " STRING(EV_CURRENT));
216 if (! elf_machine_matches_host (header->e_machine))
217 LOSE ("ELF file machine architecture not " ELF_MACHINE_NAME);
218 if (header->e_phentsize != sizeof (Elf32_Phdr))
219 LOSE ("ELF file's phentsize not the expected size");
220
221 /* Enter the new object in the list of loaded objects. */
222 l = _dl_new_object (realname, name, lt_loaded);
223 l->l_opencount = 1;
224
225 if (_dl_zerofd == -1)
226 {
227 _dl_zerofd = _dl_sysdep_open_zero_fill ();
228 if (_dl_zerofd == -1)
229 _dl_signal_error (errno, NULL, "cannot open zero fill device");
230 }
231
232 {
233 /* Copy the program header table into stack space so we can then unmap
234 the headers. */
235 Elf32_Phdr phdr[header->e_phnum];
236 const Elf32_Phdr *ph;
237 int anywhere;
238
239 ph = map (header->e_phoff, header->e_phnum * sizeof (Elf32_Phdr));
240 memcpy (phdr, ph, sizeof phdr);
241 l->l_phnum = header->e_phnum;
242
243 anywhere = header->e_type == ET_DYN || header->e_type == ET_REL;
244
245 if (entry_point)
246 *entry_point = header->e_entry;
247
248 /* We are done reading the file's headers now. Unmap them. */
249 munmap (file_mapping, mapping_size);
250
251 /* Scan the program header table, processing its load commands. */
252 l->l_addr = 0;
253 l->l_ld = 0;
254 for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
255 switch (ph->p_type)
256 {
257 /* These entries tell us where to find things once the file's
258 segments are mapped in. We record the addresses it says
259 verbatim, and later correct for the run-time load address. */
260 case PT_DYNAMIC:
261 l->l_ld = (void *) ph->p_vaddr;
262 break;
263 case PT_PHDR:
264 l->l_phdr = (void *) ph->p_vaddr;
265 break;
266
267 case PT_LOAD:
268 /* A load command tells us to map in part of the file. */
269 if (ph->p_align % pagesize != 0)
270 LOSE ("ELF load command alignment not page-aligned");
271 if ((ph->p_vaddr - ph->p_offset) % ph->p_align)
272 LOSE ("ELF load command address/offset not properly aligned");
273 {
274 Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
275 Elf32_Addr mapend = ((ph->p_vaddr + ph->p_filesz + ph->p_align - 1)
276 & ~(ph->p_align - 1));
277 off_t mapoff = ph->p_offset & ~(ph->p_align - 1);
278 caddr_t mapat;
279 int prot = 0;
280 if (ph->p_flags & PF_R)
281 prot |= PROT_READ;
282 if (ph->p_flags & PF_W)
283 prot |= PROT_WRITE;
284 if (ph->p_flags & PF_X)
285 prot |= PROT_EXEC;
286
287 if (anywhere)
288 {
289 /* XXX this loses if the first segment mmap call puts
290 it someplace where the later segments cannot fit. */
291 mapat = mmap ((caddr_t) (l->l_addr + mapstart),
292 mapend - mapstart,
293 prot, MAP_COPY|MAP_FILE|MAP_INHERIT |
294 /* Let the system choose any convenient
295 location if this is the first segment.
296 Following segments must be contiguous in
297 virtual space with the first. */
298 (l->l_addr == 0 ? 0 : MAP_FIXED),
299 fd, mapoff);
300 if (l->l_addr == 0)
301 /* This was the first segment mapped, so MAPAT is
302 the address the system chose for us. Record it. */
303 l->l_addr = (Elf32_Addr) mapat - mapstart;
304 }
305 else
306 {
307 mapat = mmap ((caddr_t) mapstart, mapend - mapstart,
308 prot, MAP_COPY|MAP_FILE|MAP_INHERIT|MAP_FIXED,
309 fd, mapoff);
310 /* This file refers to absolute addresses. So consider its
311 "load base" to be zero, since that is what we add to the
312 file's addresses to find them in our memory. */
313 l->l_addr = 0;
314 }
315 if (mapat == (caddr_t) -1)
316 lose (errno, "failed to map segment from shared object");
317
318 if (ph->p_memsz > ph->p_filesz)
319 {
320 /* Extra zero pages should appear at the end of this segment,
321 after the data mapped from the file. */
322 caddr_t zero, zeroend, zeropage;
323
324 mapat += ph->p_vaddr - mapstart;
325 zero = mapat + ph->p_filesz;
326 zeroend = mapat + ph->p_memsz;
327 zeropage = (caddr_t) ((Elf32_Addr) (zero + pagesize - 1)
328 & ~(pagesize - 1));
329
330 if (zeroend < zeropage)
331 /* All the extra data is in the last page of the segment.
332 We can just zero it. */
333 zeropage = zeroend;
334 if (zeropage > zero)
335 {
336 /* Zero the final part of the last page of the segment. */
337 if ((prot & PROT_WRITE) == 0)
338 {
339 /* Dag nab it. */
340 if (mprotect ((caddr_t) ((Elf32_Addr) zero
341 & ~(pagesize - 1)),
342 pagesize,
343 prot|PROT_WRITE) < 0)
344 lose (errno, "cannot change memory protections");
345 }
346 memset (zero, 0, zeropage - zero);
347 if ((prot & PROT_WRITE) == 0)
348 mprotect ((caddr_t) ((Elf32_Addr) zero
349 & ~(pagesize - 1)),
350 pagesize, prot);
351 }
352
353 if (zeroend > zeropage)
354 /* Map the remaining zero pages in from the zero fill FD. */
355 mapat = mmap (zeropage, zeroend - zeropage,
356 prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
357 _dl_zerofd, 0);
358 }
359 }
360 }
361
362 if (l->l_ld == 0)
363 LOSE ("object file has no dynamic section");
364 (Elf32_Addr) l->l_ld += l->l_addr;
365
366 if (l->l_phdr == 0)
367 l->l_phdr = (void *) ((const Elf32_Ehdr *) l->l_addr)->e_phoff;
368 (Elf32_Addr) l->l_phdr += l->l_addr;
369 }
370
371 elf_get_dynamic_info (l->l_ld, l->l_info);
372 if (l->l_info[DT_HASH])
373 _dl_setup_hash (l);
374
375 return l;
376 }
This page took 0.055424 seconds and 5 git commands to generate.