1/* Set up the data structures for the system-supplied DSO.
2 Copyright (C) 2012-2017 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 Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19static inline void __attribute__ ((always_inline))
20setup_vdso (struct link_map *main_map __attribute__ ((unused)),
21 struct link_map ***first_preload __attribute__ ((unused)))
22{
23#ifdef NEED_DL_SYSINFO_DSO
24 if (GLRO(dl_sysinfo_dso) == NULL)
25 return;
26
27 /* Do an abridged version of the work _dl_map_object_from_fd would do
28 to map in the object. It's already mapped and prelinked (and
29 better be, since it's read-only and so we couldn't relocate it).
30 We just want our data structures to describe it as if we had just
31 mapped and relocated it normally. */
32 struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
33 0, LM_ID_BASE);
34 if (__glibc_likely (l != NULL))
35 {
36 static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
37
38 l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso)
39 + GLRO(dl_sysinfo_dso)->e_phoff);
40 l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum;
41 for (uint_fast16_t i = 0; i < l->l_phnum; ++i)
42 {
43 const ElfW(Phdr) *const ph = &l->l_phdr[i];
44 if (ph->p_type == PT_DYNAMIC)
45 {
46 l->l_ld = (void *) ph->p_vaddr;
47 l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
48 }
49 else if (ph->p_type == PT_LOAD)
50 {
51 if (! l->l_addr)
52 l->l_addr = ph->p_vaddr;
53 if (ph->p_vaddr + ph->p_memsz >= l->l_map_end)
54 l->l_map_end = ph->p_vaddr + ph->p_memsz;
55 if ((ph->p_flags & PF_X)
56 && ph->p_vaddr + ph->p_memsz >= l->l_text_end)
57 l->l_text_end = ph->p_vaddr + ph->p_memsz;
58 }
59 else
60 /* There must be no TLS segment. */
61 assert (ph->p_type != PT_TLS);
62 }
63 l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso);
64 l->l_addr = l->l_map_start - l->l_addr;
65 l->l_map_end += l->l_addr;
66 l->l_text_end += l->l_addr;
67 l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
68 elf_get_dynamic_info (l, dyn_temp);
69 _dl_setup_hash (l);
70 l->l_relocated = 1;
71
72 /* The vDSO is always used. */
73 l->l_used = 1;
74
75 /* Initialize l_local_scope to contain just this map. This allows
76 the use of dl_lookup_symbol_x to resolve symbols within the vdso.
77 So we create a single entry list pointing to l_real as its only
78 element */
79 l->l_local_scope[0]->r_nlist = 1;
80 l->l_local_scope[0]->r_list = &l->l_real;
81
82 /* Now that we have the info handy, use the DSO image's soname
83 so this object can be looked up by name. Note that we do not
84 set l_name here. That field gives the file name of the DSO,
85 and this DSO is not associated with any file. */
86 if (l->l_info[DT_SONAME] != NULL)
87 {
88 /* Work around a kernel problem. The kernel cannot handle
89 addresses in the vsyscall DSO pages in writev() calls. */
90 const char *dsoname = ((char *) D_PTR (l, l_info[DT_STRTAB])
91 + l->l_info[DT_SONAME]->d_un.d_val);
92 size_t len = strlen (dsoname) + 1;
93 char *copy = malloc (len);
94 if (copy == NULL)
95 _dl_fatal_printf ("out of memory\n");
96 l->l_libname->name = l->l_name = memcpy (copy, dsoname, len);
97 }
98
99 /* Add the vDSO to the object list. */
100 _dl_add_to_namespace_list (l, LM_ID_BASE);
101
102# if IS_IN (rtld)
103 /* Rearrange the list so this DSO appears after rtld_map. */
104 assert (l->l_next == NULL);
105 assert (l->l_prev == main_map);
106 GL(dl_rtld_map).l_next = l;
107 l->l_prev = &GL(dl_rtld_map);
108 *first_preload = &l->l_next;
109# else
110 GL(dl_nns) = 1;
111# endif
112
113 /* We have a prelinked DSO preloaded by the system. */
114 GLRO(dl_sysinfo_map) = l;
115# ifdef NEED_DL_SYSINFO
116 if (GLRO(dl_sysinfo) == DL_SYSINFO_DEFAULT)
117 GLRO(dl_sysinfo) = GLRO(dl_sysinfo_dso)->e_entry + l->l_addr;
118# endif
119 }
120#endif
121}
122