(rtld_map): New static variable.
[kopensolaris-gnu/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;
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   buf = alloca (strlen (dirpath) + 1 + namelen);
69   do
70     {
71       dirpath = p;
72       p = strpbrk (dirpath, ":;");
73       if (p == NULL)
74         p = strchr (dirpath, '\0');
75
76       if (p == dirpath)
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);
80       else
81         {
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);
86         }
87
88       fd = open (buf, O_RDONLY);
89       if (fd != -1)
90         {
91           *realname = strdup (buf);
92           return fd;
93         }
94       if (errno != ENOENT && errno != EACCES)
95         /* The file exists and is readable, but something went wrong.  */
96         return -1;
97     }
98   while (*p++ != '\0');
99
100   return -1;
101 }
102
103
104 /* Map in the shared object file NAME.  */
105
106 struct link_map *
107 _dl_map_object (struct link_map *loader, const char *name)
108 {
109   int fd;
110   char *realname;
111   struct link_map *l;
112
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))
116       {
117         /* The object is already loaded.
118            Just bump its reference count and return it.  */
119         ++l->l_opencount;
120         return l;
121       }
122
123   if (strchr (name, '/') == NULL)
124     {
125       /* Search for NAME in several places.  */
126
127       size_t namelen = strlen (name) + 1;
128
129       inline void trypath (const char *dirpath)
130         {
131           fd = open_path (name, namelen, dirpath, &realname);
132         }
133
134       fd = -1;
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"));
141       if (fd == -1)
142         trypath ("/lib:/usr/lib");
143     }
144   else
145     {
146       fd = open (name, O_RDONLY);
147       if (fd != -1)
148         realname = strdup (name);
149     }
150
151   if (fd == -1)
152     _dl_signal_error (errno, name, "cannot open shared object file");
153
154   return _dl_map_object_from_fd (name, fd, realname);
155 }
156
157
158 /* Map in the shared object NAME, actually located in REALNAME, and already
159    opened on FD.  */
160
161 struct link_map *
162 _dl_map_object_from_fd (const char *name, int fd, char *realname)
163 {
164   struct link_map *l = NULL;
165   const size_t pagesize = getpagesize ();
166   void *file_mapping = NULL;
167   size_t mapping_size = 0;
168
169 #define LOSE(s) lose (0, (s))
170   void lose (int code, const char *msg)
171     {
172       (void) close (fd);
173       if (file_mapping)
174         munmap (file_mapping, mapping_size);
175       _dl_signal_error (code, l ? l->l_name : name, msg);
176     }
177
178   inline caddr_t map_segment (Elf32_Addr mapstart, size_t len,
179                               int prot, int fixed, off_t offset)
180     {
181       caddr_t mapat = mmap ((caddr_t) mapstart, len, prot,
182                             fixed|MAP_COPY|MAP_FILE|MAP_INHERIT,
183                             fd, offset);
184       if (mapat == (caddr_t) -1)
185         lose (errno, "failed to map segment from shared object");
186       return mapat;
187     }
188
189   /* Make sure LOCATION is mapped in.  */
190   void *map (off_t location, size_t size)
191     {
192       if ((off_t) mapping_size <= location + (off_t) size)
193         {
194           void *result;
195           if (file_mapping)
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;
204         }
205       return file_mapping + location;
206     }
207
208   const Elf32_Ehdr *header;
209   const Elf32_Phdr *phdr;
210   const Elf32_Phdr *ph;
211   int type;
212
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))
216       {
217         /* The object is already loaded.
218            Just bump its reference count and return it.  */
219         close (fd);
220         free (realname);
221         ++l->l_opencount;
222         return l;
223       }
224
225   /* Map in the first page to read the header.  */
226   header = map (0, sizeof *header);
227
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");
246
247   /* Enter the new object in the list of loaded objects.  */
248   l = _dl_new_object (realname, name, lt_loaded);
249   l->l_opencount = 1;
250
251   if (_dl_zerofd == -1)
252     {
253       _dl_zerofd = _dl_sysdep_open_zero_fill ();
254       if (_dl_zerofd == -1)
255         _dl_signal_error (errno, NULL, "cannot open zero fill device");
256     }
257
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));
264
265   {
266     /* Scan the program header table, collecting its load commands.  */
267     struct loadcmd
268       {
269         Elf32_Addr mapstart, mapend, dataend, allocend;
270         off_t mapoff;
271         int prot;
272       } loadcmds[l->l_phnum], *c;
273     size_t nloadcmds = 0;
274
275     l->l_ld = 0;
276     l->l_phdr = 0;
277     l->l_addr = 0;
278     for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
279       switch (ph->p_type)
280         {
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.  */
284         case PT_DYNAMIC:
285           l->l_ld = (void *) ph->p_vaddr;
286           break;
287         case PT_PHDR:
288           l->l_phdr = (void *) ph->p_vaddr;
289           break;
290
291         case PT_LOAD:
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");
298           {
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);
306             c->prot = 0;
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;
313             break;
314           }
315         }
316
317     /* We are done reading the file's headers now.  Unmap them.  */
318     munmap (file_mapping, mapping_size);
319
320     /* Now process the load commands and map segments into memory.  */
321     c = loadcmds;
322
323     if (type == ET_DYN || type == ET_REL)
324       {
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.  */
332         caddr_t mapat;
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;
337
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);
343         goto postmap;
344       }
345
346     while (c < &loadcmds[nloadcmds])
347       {
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);
352
353       postmap:
354         if (c->allocend > c->dataend)
355           {
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;
359
360             zero = l->l_addr + c->dataend;
361             zeroend = l->l_addr + c->allocend;
362             zeropage = (zero + pagesize - 1) & ~(pagesize - 1);
363
364             if (zeroend < zeropage)
365               /* All the extra data is in the last page of the segment.
366                  We can just zero it.  */
367               zeropage = zeroend;
368
369             if (zeropage > zero)
370               {
371                 /* Zero the final part of the last page of the segment.  */
372                 if ((c->prot & PROT_WRITE) == 0)
373                   {
374                     /* Dag nab it.  */
375                     if (mprotect ((caddr_t) (zero & ~(pagesize - 1)),
376                                   pagesize, c->prot|PROT_WRITE) < 0)
377                       lose (errno, "cannot change memory protections");
378                   }
379                 memset ((void *) zero, 0, zeropage - zero);
380                 if ((c->prot & PROT_WRITE) == 0)
381                   mprotect ((caddr_t) (zero & ~(pagesize - 1)),
382                             pagesize, c->prot);
383               }
384
385             if (zeroend > zeropage)
386               {
387                 /* Map the remaining zero pages in from the zero fill FD.  */
388                 caddr_t mapat;
389                 mapat = mmap ((caddr_t) zeropage, zeroend - zeropage, c->prot,
390                               MAP_ANON|MAP_PRIVATE|MAP_FIXED|MAP_INHERIT,
391                               _dl_zerofd, 0);
392                 if (mapat == (caddr_t) -1)
393                   lose (errno, "cannot map zero pages");
394               }
395           }
396
397         ++c;
398       }
399   }
400
401   if (l->l_ld == 0)
402     {
403       if (type == ET_DYN)
404         LOSE ("object file has no dynamic section");
405     }
406   else
407     (Elf32_Addr) l->l_ld += l->l_addr;
408
409   if (l->l_phdr == 0)
410     l->l_phdr = (void *) ((const Elf32_Ehdr *) l->l_addr)->e_phoff;
411   (Elf32_Addr) l->l_phdr += l->l_addr;
412
413   elf_get_dynamic_info (l->l_ld, l->l_info);
414   if (l->l_info[DT_HASH])
415     _dl_setup_hash (l);
416
417   return l;
418 }