]> sourceware.org Git - glibc.git/blob - elf/dl-load.c
Sat May 6 11:06:47 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 void trypath (const char *dirpath)
162 {
163 fd = open_path (name, namelen, dirpath, &realname);
164 }
165
166 if (loader && loader->l_info[DT_RPATH])
167 trypath ((const char *) (loader->l_addr +
168 loader->l_info[DT_RPATH]->d_un.d_ptr));
169 if (fd == -1 && ! _dl_secure)
170 trypath (getenv ("LD_LIBRARY_PATH"));
171 if (fd == -1)
172 trypath ("/lib:/usr/lib");
173 }
174 else
175 {
176 fd = open (name, O_RDONLY);
177 if (fd != -1)
178 realname = strdup (name);
179 }
180
181 if (fd == -1)
182 lose (errno, "cannot open shared object file");
183
184 /* Look again to see if the real name matched another already loaded. */
185 for (l = _dl_loaded; l; l = l->l_next)
186 if (! strcmp (realname, l->l_name))
187 {
188 /* The object is already loaded.
189 Just bump its reference count and return it. */
190 close (fd);
191 ++l->l_opencount;
192 return l;
193 }
194
195
196 /* Map in the first page to read the header. */
197 header = map (0, sizeof *header);
198
199 #undef LOSE
200 #define LOSE(s) lose (0, (s))
201 /* Check the header for basic validity. */
202 if (*(Elf32_Word *) &header->e_ident != ((ELFMAG0 << (EI_MAG0 * 8)) |
203 (ELFMAG1 << (EI_MAG1 * 8)) |
204 (ELFMAG2 << (EI_MAG2 * 8)) |
205 (ELFMAG3 << (EI_MAG3 * 8))))
206 LOSE ("invalid ELF header");
207 if (header->e_ident[EI_CLASS] != ELFCLASS32)
208 LOSE ("ELF file class not 32-bit");
209 if (header->e_ident[EI_DATA] != byteorder)
210 LOSE ("ELF file data encoding not " byteorder_name);
211 if (header->e_ident[EI_VERSION] != EV_CURRENT)
212 LOSE ("ELF file version ident not " STRING(EV_CURRENT));
213 if (header->e_version != EV_CURRENT)
214 LOSE ("ELF file version not " STRING(EV_CURRENT));
215 if (! elf_machine_matches_host (header->e_machine))
216 LOSE ("ELF file machine architecture not " ELF_MACHINE_NAME);
217 if (header->e_phentsize != sizeof (Elf32_Phdr))
218 LOSE ("ELF file's phentsize not the expected size");
219
220 /* Enter the new object in the list of loaded objects. */
221 l = _dl_new_object (realname, name, lt_loaded);
222 l->l_opencount = 1;
223
224 if (_dl_zerofd == -1)
225 {
226 _dl_zerofd = _dl_sysdep_open_zero_fill ();
227 if (_dl_zerofd == -1)
228 _dl_signal_error (errno, NULL, "cannot open zero fill device");
229 }
230
231 {
232 /* Copy the program header table into stack space so we can then unmap
233 the headers. */
234 Elf32_Phdr phdr[header->e_phnum];
235 const Elf32_Phdr *ph;
236 int anywhere;
237
238 ph = map (header->e_phoff, header->e_phnum * sizeof (Elf32_Phdr));
239 memcpy (phdr, ph, sizeof phdr);
240 l->l_phnum = header->e_phnum;
241
242 anywhere = header->e_type == ET_DYN || header->e_type == ET_REL;
243
244 if (entry_point)
245 *entry_point = header->e_entry;
246
247 /* We are done reading the file's headers now. Unmap them. */
248 munmap (file_mapping, mapping_size);
249
250 /* Scan the program header table, processing its load commands. */
251 l->l_addr = 0;
252 l->l_ld = 0;
253 for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
254 switch (ph->p_type)
255 {
256 /* These entries tell us where to find things once the file's
257 segments are mapped in. We record the addresses it says
258 verbatim, and later correct for the run-time load address. */
259 case PT_DYNAMIC:
260 l->l_ld = (void *) ph->p_vaddr;
261 break;
262 case PT_PHDR:
263 l->l_phdr = (void *) ph->p_vaddr;
264 break;
265
266 case PT_LOAD:
267 /* A load command tells us to map in part of the file. */
268 if (ph->p_align % pagesize != 0)
269 LOSE ("ELF load command alignment not page-aligned");
270 if ((ph->p_vaddr - ph->p_offset) % ph->p_align)
271 LOSE ("ELF load command address/offset not properly aligned");
272 {
273 Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
274 Elf32_Addr mapend = ((ph->p_vaddr + ph->p_filesz + ph->p_align - 1)
275 & ~(ph->p_align - 1));
276 off_t mapoff = ph->p_offset & ~(ph->p_align - 1);
277 caddr_t mapat;
278 int prot = 0;
279 if (ph->p_flags & PF_R)
280 prot |= PROT_READ;
281 if (ph->p_flags & PF_W)
282 prot |= PROT_WRITE;
283 if (ph->p_flags & PF_X)
284 prot |= PROT_EXEC;
285
286 if (anywhere)
287 {
288 /* XXX this loses if the first segment mmap call puts
289 it someplace where the later segments cannot fit. */
290 mapat = mmap ((caddr_t) (l->l_addr + mapstart),
291 mapend - mapstart,
292 prot, MAP_COPY|MAP_FILE|MAP_INHERIT |
293 /* Let the system choose any convenient
294 location if this is the first segment.
295 Following segments must be contiguous in
296 virtual space with the first. */
297 (l->l_addr == 0 ? 0 : MAP_FIXED),
298 fd, mapoff);
299 if (l->l_addr == 0)
300 /* This was the first segment mapped, so MAPAT is
301 the address the system chose for us. Record it. */
302 l->l_addr = (Elf32_Addr) mapat - mapstart;
303 }
304 else
305 {
306 mapat = mmap ((caddr_t) mapstart, mapend - mapstart,
307 prot, MAP_COPY|MAP_FILE|MAP_INHERIT|MAP_FIXED,
308 fd, mapoff);
309 /* This file refers to absolute addresses. So consider its
310 "load base" to be zero, since that is what we add to the
311 file's addresses to find them in our memory. */
312 l->l_addr = 0;
313 }
314 if (mapat == (caddr_t) -1)
315 lose (errno, "failed to map segment from shared object");
316
317 if (ph->p_memsz > ph->p_filesz)
318 {
319 /* Extra zero pages should appear at the end of this segment,
320 after the data mapped from the file. Adjust MAPEND to map
321 only the data from the file. We will later allocate zero
322 pages following the data mapping. */
323 caddr_t zero = mapat - mapstart + ph->p_filesz;
324 caddr_t zeroend = mapat - mapstart + ph->p_memsz;
325 caddr_t zeropage
326 = (caddr_t) ((Elf32_Addr) (zero + pagesize - 1)
327 & ~(pagesize - 1));
328
329 if (zeroend < zeropage)
330 /* All the extra data is in the last page of the segment.
331 We can just zero it. */
332 zeropage = zeroend;
333 if (zeropage > zero)
334 {
335 /* Zero the final part of the last page of the segment. */
336 if ((prot & PROT_WRITE) == 0)
337 {
338 /* Dag nab it. */
339 if (mprotect ((caddr_t) ((Elf32_Addr) zero
340 & ~(pagesize - 1)),
341 pagesize,
342 prot|PROT_WRITE) < 0)
343 lose (errno, "cannot change memory protections");
344 }
345 memset (zero, 0, zeroend - zero);
346 if ((prot & PROT_WRITE) == 0)
347 mprotect ((caddr_t) ((Elf32_Addr) zero
348 & ~(pagesize - 1)),
349 pagesize, prot);
350 }
351
352 if (zeroend > zeropage)
353 /* Map the remaining zero pages in from the zero fill FD. */
354 mapat = mmap (zeropage, zeroend - zeropage,
355 prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
356 _dl_zerofd, 0);
357 }
358 }
359 }
360
361 if (l->l_ld == 0)
362 LOSE ("object file has no dynamic section");
363 (Elf32_Addr) l->l_ld += l->l_addr;
364
365 if (l->l_phdr == 0)
366 l->l_phdr = (void *) ((const Elf32_Ehdr *) l->l_addr)->e_phoff;
367 (Elf32_Addr) l->l_phdr += l->l_addr;
368 }
369
370 elf_get_dynamic_info (l->l_ld, l->l_info);
371 if (l->l_info[DT_HASH])
372 _dl_setup_hash (l);
373
374 return l;
375 }
This page took 0.061297 seconds and 6 git commands to generate.