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.
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.
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.
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. */
21 #include <sys/types.h>
28 #include "dynamic-link.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"
39 #error "Unknown BYTE_ORDER " BYTE_ORDER
40 #define byteorder ELFDATANONE
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. */
53 open_path (const char *name, size_t namelen,
62 if (p == NULL || *p == '\0')
68 buf = alloca (strlen (dirpath) + 1 + namelen);
72 p = strpbrk (dirpath, ":;");
74 p = strchr (dirpath, '\0');
77 /* Two adjacent colons, or a colon at the beginning or the end of
78 the path means to search the current directory. */
79 (void) memcpy (buf, name, namelen);
82 /* Construct the pathname to try. */
83 (void) memcpy (buf, dirpath, p - dirpath);
84 buf[p - dirpath] = '/';
85 (void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
88 fd = open (buf, O_RDONLY);
91 *realname = strdup (buf);
94 if (errno != ENOENT && errno != EACCES)
95 /* The file exists and is readable, but something went wrong. */
104 /* Map in the shared object file NAME. */
107 _dl_map_object (struct link_map *loader, const char *name)
113 /* Look for this name among those already loaded. */
114 for (l = _dl_loaded; l; l = l->l_next)
115 if (! strcmp (name, l->l_libname))
117 /* The object is already loaded.
118 Just bump its reference count and return it. */
123 if (strchr (name, '/') == NULL)
125 /* Search for NAME in several places. */
127 size_t namelen = strlen (name) + 1;
129 inline void trypath (const char *dirpath)
131 fd = open_path (name, namelen, dirpath, &realname);
135 if (loader && loader->l_info[DT_RPATH])
136 trypath ((const char *) (loader->l_addr +
137 loader->l_info[DT_STRTAB]->d_un.d_ptr +
138 loader->l_info[DT_RPATH]->d_un.d_val));
139 if (fd == -1 && ! _dl_secure)
140 trypath (getenv ("LD_LIBRARY_PATH"));
142 trypath ("/lib:/usr/lib");
146 fd = open (name, O_RDONLY);
148 realname = strdup (name);
152 _dl_signal_error (errno, name, "cannot open shared object file");
154 return _dl_map_object_from_fd (name, fd, realname);
158 /* Map in the shared object NAME, actually located in REALNAME, and already
162 _dl_map_object_from_fd (const char *name, int fd, char *realname)
164 struct link_map *l = NULL;
165 const size_t pagesize = getpagesize ();
166 void *file_mapping = NULL;
167 size_t mapping_size = 0;
169 #define LOSE(s) lose (0, (s))
170 void lose (int code, const char *msg)
174 munmap (file_mapping, mapping_size);
175 _dl_signal_error (code, l ? l->l_name : name, msg);
178 inline caddr_t map_segment (Elf32_Addr mapstart, size_t len,
179 int prot, int fixed, off_t offset)
181 caddr_t mapat = mmap ((caddr_t) mapstart, len, prot,
182 fixed|MAP_COPY|MAP_FILE|MAP_INHERIT,
184 if (mapat == (caddr_t) -1)
185 lose (errno, "failed to map segment from shared object");
189 /* Make sure LOCATION is mapped in. */
190 void *map (off_t location, size_t size)
192 if ((off_t) mapping_size <= location + (off_t) size)
196 munmap (file_mapping, mapping_size);
197 mapping_size = (location + size + 1 + pagesize - 1);
198 mapping_size &= ~(pagesize - 1);
199 result = mmap (file_mapping, mapping_size, PROT_READ,
200 MAP_COPY|MAP_FILE, fd, 0);
201 if (result == (void *) -1)
202 lose (errno, "cannot map file data");
203 file_mapping = result;
205 return file_mapping + location;
208 const Elf32_Ehdr *header;
209 const Elf32_Phdr *phdr;
210 const Elf32_Phdr *ph;
213 /* Look again to see if the real name matched another already loaded. */
214 for (l = _dl_loaded; l; l = l->l_next)
215 if (! strcmp (realname, l->l_name))
217 /* The object is already loaded.
218 Just bump its reference count and return it. */
225 /* Map in the first page to read the header. */
226 header = map (0, sizeof *header);
228 /* Check the header for basic validity. */
229 if (*(Elf32_Word *) &header->e_ident != ((ELFMAG0 << (EI_MAG0 * 8)) |
230 (ELFMAG1 << (EI_MAG1 * 8)) |
231 (ELFMAG2 << (EI_MAG2 * 8)) |
232 (ELFMAG3 << (EI_MAG3 * 8))))
233 LOSE ("invalid ELF header");
234 if (header->e_ident[EI_CLASS] != ELFCLASS32)
235 LOSE ("ELF file class not 32-bit");
236 if (header->e_ident[EI_DATA] != byteorder)
237 LOSE ("ELF file data encoding not " byteorder_name);
238 if (header->e_ident[EI_VERSION] != EV_CURRENT)
239 LOSE ("ELF file version ident not " STRING(EV_CURRENT));
240 if (header->e_version != EV_CURRENT)
241 LOSE ("ELF file version not " STRING(EV_CURRENT));
242 if (! elf_machine_matches_host (header->e_machine))
243 LOSE ("ELF file machine architecture not " ELF_MACHINE_NAME);
244 if (header->e_phentsize != sizeof (Elf32_Phdr))
245 LOSE ("ELF file's phentsize not the expected size");
247 /* Enter the new object in the list of loaded objects. */
248 l = _dl_new_object (realname, name, lt_loaded);
251 if (_dl_zerofd == -1)
253 _dl_zerofd = _dl_sysdep_open_zero_fill ();
254 if (_dl_zerofd == -1)
255 _dl_signal_error (errno, NULL, "cannot open zero fill device");
258 /* Extract the remaining details we need from the ELF header
259 and then map in the program header table. */
260 l->l_entry = header->e_entry;
261 type = header->e_type;
262 l->l_phnum = header->e_phnum;
263 phdr = map (header->e_phoff, l->l_phnum * sizeof (Elf32_Phdr));
266 /* Scan the program header table, collecting its load commands. */
269 Elf32_Addr mapstart, mapend, dataend, allocend;
272 } loadcmds[l->l_phnum], *c;
273 size_t nloadcmds = 0;
278 for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
281 /* These entries tell us where to find things once the file's
282 segments are mapped in. We record the addresses it says
283 verbatim, and later correct for the run-time load address. */
285 l->l_ld = (void *) ph->p_vaddr;
288 l->l_phdr = (void *) ph->p_vaddr;
292 /* A load command tells us to map in part of the file.
293 We record the load commands and process them all later. */
294 if (ph->p_align % pagesize != 0)
295 LOSE ("ELF load command alignment not page-aligned");
296 if ((ph->p_vaddr - ph->p_offset) % ph->p_align)
297 LOSE ("ELF load command address/offset not properly aligned");
299 struct loadcmd *c = &loadcmds[nloadcmds++];
300 c->mapstart = ph->p_vaddr & ~(ph->p_align - 1);
301 c->mapend = ((ph->p_vaddr + ph->p_filesz + ph->p_align - 1)
302 & ~(ph->p_align - 1));
303 c->dataend = ph->p_vaddr + ph->p_filesz;
304 c->allocend = ph->p_vaddr + ph->p_memsz;
305 c->mapoff = ph->p_offset & ~(ph->p_align - 1);
307 if (ph->p_flags & PF_R)
308 c->prot |= PROT_READ;
309 if (ph->p_flags & PF_W)
310 c->prot |= PROT_WRITE;
311 if (ph->p_flags & PF_X)
312 c->prot |= PROT_EXEC;
317 /* We are done reading the file's headers now. Unmap them. */
318 munmap (file_mapping, mapping_size);
320 /* Now process the load commands and map segments into memory. */
323 if (type == ET_DYN || type == ET_REL)
325 /* This is a position-independent shared object. We can let the
326 kernel map it anywhere it likes, but we must have space for all
327 the segments in their specified positions relative to the first.
328 So we map the first segment without MAP_FIXED, but with its
329 extent increased to cover all the segments. Then we unmap the
330 excess portion, and there is known sufficient space there to map
331 the later segments. */
333 mapat = map_segment (c->mapstart,
334 loadcmds[nloadcmds - 1].allocend - c->mapstart,
335 c->prot, 0, c->mapoff);
336 l->l_addr = (Elf32_Addr) mapat - c->mapstart;
338 /* Unmap the excess portion, and then jump into the normal
339 segment-mapping loop to handle the portion of the segment past
340 the end of the file mapping. */
341 munmap (mapat + c->mapend,
342 loadcmds[nloadcmds - 1].allocend - c->mapend);
346 while (c < &loadcmds[nloadcmds])
348 if (c->mapend > c->mapstart)
349 /* Map the segment contents from the file. */
350 map_segment (l->l_addr + c->mapstart, c->mapend - c->mapstart,
351 c->prot, MAP_FIXED, c->mapoff);
354 if (c->allocend > c->dataend)
356 /* Extra zero pages should appear at the end of this segment,
357 after the data mapped from the file. */
358 Elf32_Addr zero, zeroend, zeropage;
360 zero = l->l_addr + c->dataend;
361 zeroend = l->l_addr + c->allocend;
362 zeropage = (zero + pagesize - 1) & ~(pagesize - 1);
364 if (zeroend < zeropage)
365 /* All the extra data is in the last page of the segment.
366 We can just zero it. */
371 /* Zero the final part of the last page of the segment. */
372 if ((c->prot & PROT_WRITE) == 0)
375 if (mprotect ((caddr_t) (zero & ~(pagesize - 1)),
376 pagesize, c->prot|PROT_WRITE) < 0)
377 lose (errno, "cannot change memory protections");
379 memset ((void *) zero, 0, zeropage - zero);
380 if ((c->prot & PROT_WRITE) == 0)
381 mprotect ((caddr_t) (zero & ~(pagesize - 1)),
385 if (zeroend > zeropage)
387 /* Map the remaining zero pages in from the zero fill FD. */
389 mapat = mmap ((caddr_t) zeropage, zeroend - zeropage, c->prot,
390 MAP_ANON|MAP_PRIVATE|MAP_FIXED|MAP_INHERIT,
392 if (mapat == (caddr_t) -1)
393 lose (errno, "cannot map zero pages");
404 LOSE ("object file has no dynamic section");
407 (Elf32_Addr) l->l_ld += l->l_addr;
410 l->l_phdr = (void *) ((const Elf32_Ehdr *) l->l_addr)->e_phoff;
411 (Elf32_Addr) l->l_phdr += l->l_addr;
413 elf_get_dynamic_info (l->l_ld, l->l_info);
414 if (l->l_info[DT_HASH])