1 /* Do relocations for ELF dynamic linking.
2    Copyright (C) 1995-2021 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    <https://www.gnu.org/licenses/>.  */
18 
19 /* This file may be included twice, to define both
20    `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.  */
21 
22 #ifdef DO_RELA
23 # define elf_dynamic_do_Rel		elf_dynamic_do_Rela
24 # define Rel				Rela
25 # define elf_machine_rel		elf_machine_rela
26 # define elf_machine_rel_relative	elf_machine_rela_relative
27 #endif
28 
29 #ifndef DO_ELF_MACHINE_REL_RELATIVE
30 # define DO_ELF_MACHINE_REL_RELATIVE(map, l_addr, relative) \
31   elf_machine_rel_relative (l_addr, relative,				      \
32 			    (void *) (l_addr + relative->r_offset))
33 #endif
34 
35 /* Perform the relocations in MAP on the running program image as specified
36    by RELTAG, SZTAG.  If LAZY is nonzero, this is the first pass on PLT
37    relocations; they should be set up to call _dl_runtime_resolve, rather
38    than fully resolved now.  */
39 
40 static inline void __attribute__ ((always_inline))
41 elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
42 		    ElfW(Addr) reladdr, ElfW(Addr) relsize,
43 		    __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
44 		    int lazy, int skip_ifunc)
45 {
46   const ElfW(Rel) *r = (const void *) reladdr;
47   const ElfW(Rel) *end = (const void *) (reladdr + relsize);
48   ElfW(Addr) l_addr = map->l_addr;
49 # if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
50   const ElfW(Rel) *r2 = NULL;
51   const ElfW(Rel) *end2 = NULL;
52 # endif
53 
54 #if (!defined DO_RELA || !defined ELF_MACHINE_PLT_REL) && !defined RTLD_BOOTSTRAP
55   /* We never bind lazily during ld.so bootstrap.  Unfortunately gcc is
56      not clever enough to see through all the function calls to realize
57      that.  */
58   if (lazy)
59     {
60       /* Doing lazy PLT relocations; they need very little info.  */
61       for (; r < end; ++r)
62 # ifdef ELF_MACHINE_IRELATIVE
63 	if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
64 	  {
65 	    if (r2 == NULL)
66 	      r2 = r;
67 	    end2 = r;
68 	  }
69 	else
70 # endif
71 	  elf_machine_lazy_rel (map, scope, l_addr, r, skip_ifunc);
72 
73 # ifdef ELF_MACHINE_IRELATIVE
74       if (r2 != NULL)
75 	for (; r2 <= end2; ++r2)
76 	  if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
77 	    elf_machine_lazy_rel (map, scope, l_addr, r2, skip_ifunc);
78 # endif
79     }
80   else
81 #endif
82     {
83       const ElfW(Sym) *const symtab =
84 	(const void *) D_PTR (map, l_info[DT_SYMTAB]);
85       const ElfW(Rel) *relative = r;
86       r += nrelative;
87 
88 #ifndef RTLD_BOOTSTRAP
89       /* This is defined in rtld.c, but nowhere in the static libc.a; make
90 	 the reference weak so static programs can still link.  This
91 	 declaration cannot be done when compiling rtld.c (i.e. #ifdef
92 	 RTLD_BOOTSTRAP) because rtld.c contains the common defn for
93 	 _dl_rtld_map, which is incompatible with a weak decl in the same
94 	 file.  */
95 # ifndef SHARED
96       weak_extern (GL(dl_rtld_map));
97 # endif
98       if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
99 # if !defined DO_RELA || defined ELF_MACHINE_REL_RELATIVE
100 	/* Rela platforms get the offset from r_addend and this must
101 	   be copied in the relocation address.  Therefore we can skip
102 	   the relative relocations only if this is for rel
103 	   relocations or rela relocations if they are computed as
104 	   memory_loc += l_addr...  */
105 	if (l_addr != 0)
106 # else
107 	/* ...or we know the object has been prelinked.  */
108 	if (l_addr != 0 || ! map->l_info[VALIDX(DT_GNU_PRELINKED)])
109 # endif
110 #endif
111 	  for (; relative < r; ++relative)
112 	    DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative);
113 
114 #ifdef RTLD_BOOTSTRAP
115       /* The dynamic linker always uses versioning.  */
116       assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
117 #else
118       if (map->l_info[VERSYMIDX (DT_VERSYM)])
119 #endif
120 	{
121 	  const ElfW(Half) *const version =
122 	    (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
123 
124 	  for (; r < end; ++r)
125 	    {
126 #if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
127 	      if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
128 		{
129 		  if (r2 == NULL)
130 		    r2 = r;
131 		  end2 = r;
132 		  continue;
133 		}
134 #endif
135 
136 	      ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
137 	      elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)],
138 			       &map->l_versions[ndx],
139 			       (void *) (l_addr + r->r_offset), skip_ifunc);
140 	    }
141 
142 #if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
143 	  if (r2 != NULL)
144 	    for (; r2 <= end2; ++r2)
145 	      if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
146 		{
147 		  ElfW(Half) ndx
148 		    = version[ELFW(R_SYM) (r2->r_info)] & 0x7fff;
149 		  elf_machine_rel (map, scope, r2,
150 				   &symtab[ELFW(R_SYM) (r2->r_info)],
151 				   &map->l_versions[ndx],
152 				   (void *) (l_addr + r2->r_offset),
153 				   skip_ifunc);
154 		}
155 #endif
156 	}
157 #ifndef RTLD_BOOTSTRAP
158       else
159 	{
160 	  for (; r < end; ++r)
161 # ifdef ELF_MACHINE_IRELATIVE
162 	    if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
163 	      {
164 		if (r2 == NULL)
165 		  r2 = r;
166 		end2 = r;
167 	      }
168 	    else
169 # endif
170 	      elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
171 			       (void *) (l_addr + r->r_offset), skip_ifunc);
172 
173 # ifdef ELF_MACHINE_IRELATIVE
174 	  if (r2 != NULL)
175 	    for (; r2 <= end2; ++r2)
176 	      if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
177 		elf_machine_rel (map, scope, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
178 				 NULL, (void *) (l_addr + r2->r_offset),
179 				 skip_ifunc);
180 # endif
181 	}
182 #endif
183     }
184 }
185 
186 #undef elf_dynamic_do_Rel
187 #undef Rel
188 #undef elf_machine_rel
189 #undef elf_machine_rel_relative
190 #undef DO_ELF_MACHINE_REL_RELATIVE
191 #undef DO_RELA
192