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