1 /* Machine-dependent ELF dynamic relocation inline functions.  m68k version.
2    Copyright (C) 1996-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 #ifndef dl_machine_h
20 #define dl_machine_h
21 
22 #define ELF_MACHINE_NAME "m68k"
23 
24 #include <sys/param.h>
25 #include <sysdep.h>
26 #include <dl-tls.h>
27 #include <dl-static-tls.h>
28 #include <dl-machine-rel.h>
29 
30 /* Return nonzero iff ELF header is compatible with the running host.  */
31 static inline int
elf_machine_matches_host(const Elf32_Ehdr * ehdr)32 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
33 {
34   return ehdr->e_machine == EM_68K;
35 }
36 
37 
38 /* Return the link-time address of _DYNAMIC.
39    This must be inlined in a function which uses global data.  */
40 static inline Elf32_Addr
elf_machine_dynamic(void)41 elf_machine_dynamic (void)
42 {
43   Elf32_Addr addr;
44 
45   asm ("move.l _DYNAMIC@GOT.w(%%a5), %0"
46        : "=a" (addr));
47   return addr;
48 }
49 
50 
51 /* Return the run-time load address of the shared object.  */
52 static inline Elf32_Addr
elf_machine_load_address(void)53 elf_machine_load_address (void)
54 {
55   Elf32_Addr addr;
56 #ifdef SHARED
57   asm (PCREL_OP ("lea", "_dl_start", "%0", "%0", "%%pc") "\n\t"
58        "sub.l _dl_start@GOT.w(%%a5), %0"
59        : "=a" (addr));
60 #else
61   asm (PCREL_OP ("lea", "_dl_relocate_static_pie", "%0", "%0", "%%pc") "\n\t"
62        "sub.l _dl_relocate_static_pie@GOT.w(%%a5), %0"
63        : "=a" (addr));
64 #endif
65   return addr;
66 }
67 
68 
69 /* Set up the loaded object described by L so its unrelocated PLT
70    entries will jump to the on-demand fixup code in dl-runtime.c.  */
71 
72 static inline int __attribute__ ((always_inline))
elf_machine_runtime_setup(struct link_map * l,struct r_scope_elem * scope[],int lazy,int profile)73 elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
74 			   int lazy, int profile)
75 {
76   Elf32_Addr *got;
77   extern void _dl_runtime_resolve (Elf32_Word);
78   extern void _dl_runtime_profile (Elf32_Word);
79 
80   if (l->l_info[DT_JMPREL] && lazy)
81     {
82       /* The GOT entries for functions in the PLT have not yet been
83 	 filled in.  Their initial contents will arrange when called
84 	 to push an offset into the .rela.plt section, push
85 	 _GLOBAL_OFFSET_TABLE_[1], and then jump to
86 	 _GLOBAL_OFFSET_TABLE_[2].  */
87       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
88       got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
89 
90       /* The got[2] entry contains the address of a function which gets
91 	 called to get the address of a so far unresolved function and
92 	 jump to it.  The profiling extension of the dynamic linker allows
93 	 to intercept the calls to collect information.  In this case we
94 	 don't store the address in the GOT so that all future calls also
95 	 end in this function.  */
96       if (profile)
97 	{
98 	  got[2] = (Elf32_Addr) &_dl_runtime_profile;
99 
100 	  if (GLRO(dl_profile) != NULL
101 	      && _dl_name_match_p (GLRO(dl_profile), l))
102 	    {
103 	      /* This is the object we are looking for.  Say that we really
104 		 want profiling and the timers are started.  */
105 	      GL(dl_profile_map) = l;
106 	    }
107 	}
108       else
109 	/* This function will get called to fix up the GOT entry indicated by
110 	   the offset on the stack, and then jump to the resolved address.  */
111 	got[2] = (Elf32_Addr) &_dl_runtime_resolve;
112     }
113 
114   return lazy;
115 }
116 
117 #define ELF_MACHINE_RUNTIME_FIXUP_ARGS long int save_a0, long int save_a1
118 #define ELF_MACHINE_RUNTIME_FIXUP_PARAMS save_a0, save_a1
119 
120 
121 /* Mask identifying addresses reserved for the user program,
122    where the dynamic linker should not map anything.  */
123 #define ELF_MACHINE_USER_ADDRESS_MASK	0x80000000UL
124 
125 /* Initial entry point code for the dynamic linker.
126    The C function `_dl_start' is the real entry point;
127    its return value is the user program's entry point.  */
128 
129 #define RTLD_START asm ("\
130 	.text\n\
131 	.globl _start\n\
132 	.type _start,@function\n\
133 _start:\n\
134 	sub.l %fp, %fp\n\
135 	move.l %sp, -(%sp)\n\
136 	jbsr _dl_start\n\
137 	addq.l #4, %sp\n\
138 	/* FALLTHRU */\n\
139 \n\
140 	.globl _dl_start_user\n\
141 	.type _dl_start_user,@function\n\
142 _dl_start_user:\n\
143 	| Save the user entry point address in %a4.\n\
144 	move.l %d0, %a4\n\
145 	| Load the adjusted argument count.\n\
146 	move.l (%sp), %d1\n\
147 	# Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\
148 	pea 8(%sp, %d1*4)\n\
149 	pea 8(%sp)\n\
150 	move.l %d1, -(%sp)\n\
151 	" PCREL_OP ("move.l", "_rtld_local", "-(%sp)", "%d0", "%pc") "\n\
152 	jbsr _dl_init\n\
153 	addq.l #8, %sp\n\
154 	addq.l #8, %sp\n\
155 	| Pass our finalizer function to the user in %a1.\n\
156 	" PCREL_OP ("lea", "_dl_fini", "%a1", "%a1", "%pc") "\n\
157 	| Initialize %fp with the stack pointer.\n\
158 	move.l %sp, %fp\n\
159 	| Jump to the user's entry point.\n\
160 	jmp (%a4)\n\
161 	.size _dl_start_user, . - _dl_start_user\n\
162 	.previous");
163 
164 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
165    TLS variable, so undefined references should not be allowed to
166    define the value.
167    ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
168    of the main executable's symbols, as for a COPY reloc.  */
169 #define elf_machine_type_class(type) \
170   ((((type) == R_68K_JMP_SLOT	     \
171      || (type) == R_68K_TLS_DTPMOD32 \
172      || (type) == R_68K_TLS_DTPREL32 \
173      || (type) == R_68K_TLS_TPREL32) * ELF_RTYPE_CLASS_PLT)	\
174    | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY))
175 
176 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
177 #define ELF_MACHINE_JMP_SLOT	R_68K_JMP_SLOT
178 
179 static inline Elf32_Addr
elf_machine_fixup_plt(struct link_map * map,lookup_t t,const ElfW (Sym)* refsym,const ElfW (Sym)* sym,const Elf32_Rela * reloc,Elf32_Addr * reloc_addr,Elf32_Addr value)180 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
181 		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
182 		       const Elf32_Rela *reloc,
183 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
184 {
185   return *reloc_addr = value;
186 }
187 
188 /* Return the final value of a plt relocation.  On the m68k the JMP_SLOT
189    relocation ignores the addend.  */
190 static inline Elf32_Addr
elf_machine_plt_value(struct link_map * map,const Elf32_Rela * reloc,Elf32_Addr value)191 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
192 		       Elf32_Addr value)
193 {
194   return value;
195 }
196 
197 /* Names of the architecture-specific auditing callback functions.  */
198 #define ARCH_LA_PLTENTER m68k_gnu_pltenter
199 #define ARCH_LA_PLTEXIT m68k_gnu_pltexit
200 
201 #endif /* !dl_machine_h */
202 
203 #ifdef RESOLVE_MAP
204 
205 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
206    MAP is the object containing the reloc.  */
207 
208 static inline void __attribute__ ((unused, always_inline))
elf_machine_rela(struct link_map * map,struct r_scope_elem * scope[],const Elf32_Rela * reloc,const Elf32_Sym * sym,const struct r_found_version * version,void * const reloc_addr_arg,int skip_ifunc)209 elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
210 		  const Elf32_Rela *reloc, const Elf32_Sym *sym,
211 		  const struct r_found_version *version,
212 		  void *const reloc_addr_arg, int skip_ifunc)
213 {
214   Elf32_Addr *const reloc_addr = reloc_addr_arg;
215   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
216 
217   if (__builtin_expect (r_type == R_68K_RELATIVE, 0))
218     *reloc_addr = map->l_addr + reloc->r_addend;
219   else
220     {
221       const Elf32_Sym *const refsym = sym;
222       struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
223 					      r_type);
224       Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
225 
226       switch (r_type)
227 	{
228 	case R_68K_GLOB_DAT:
229 	case R_68K_JMP_SLOT:
230 	  *reloc_addr = value;
231 	  break;
232 #ifndef RTLD_BOOTSTRAP
233 	case R_68K_COPY:
234 	  if (sym == NULL)
235 	    /* This can happen in trace mode if an object could not be
236 	       found.  */
237 	    break;
238 	  if (sym->st_size > refsym->st_size
239 	      || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
240 	    {
241 	      const char *strtab;
242 
243 	      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
244 	      _dl_error_printf ("\
245 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
246 				RTLD_PROGNAME, strtab + refsym->st_name);
247 	    }
248 	  memcpy (reloc_addr_arg, (void *) value,
249 		  MIN (sym->st_size, refsym->st_size));
250 	  break;
251 	case R_68K_8:
252 	  *(char *) reloc_addr = value + reloc->r_addend;
253 	  break;
254 	case R_68K_16:
255 	  *(short *) reloc_addr = value + reloc->r_addend;
256 	  break;
257 	case R_68K_32:
258 	  *reloc_addr = value + reloc->r_addend;
259 	  break;
260 	case R_68K_PC8:
261 	  *(char *) reloc_addr
262 	    = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
263 	  break;
264 	case R_68K_PC16:
265 	  *(short *) reloc_addr
266 	    = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
267 	  break;
268 	case R_68K_PC32:
269 	  *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
270 	  break;
271 	case R_68K_TLS_DTPMOD32:
272 	  /* Get the information from the link map returned by the
273 	     resolv function.  */
274 	  if (sym_map != NULL)
275 	    *reloc_addr = sym_map->l_tls_modid;
276 	  break;
277 	case R_68K_TLS_DTPREL32:
278 	  if (sym != NULL)
279 	    *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
280 	  break;
281 	case R_68K_TLS_TPREL32:
282 	  if (sym != NULL)
283 	    {
284 	      CHECK_STATIC_TLS (map, sym_map);
285 	      *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
286 	    }
287 	  break;
288 	case R_68K_NONE:		/* Alright, Wilbur.  */
289 	  break;
290 #endif /* !RTLD_BOOTSTRAP */
291 	default:
292 	  _dl_reloc_bad_type (map, r_type, 0);
293 	  break;
294 	}
295     }
296 }
297 
298 static inline void __attribute__ ((unused, always_inline))
elf_machine_rela_relative(Elf32_Addr l_addr,const Elf32_Rela * reloc,void * const reloc_addr_arg)299 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
300 			   void *const reloc_addr_arg)
301 {
302   Elf32_Addr *const reloc_addr = reloc_addr_arg;
303   *reloc_addr = l_addr + reloc->r_addend;
304 }
305 
306 static inline void __attribute__ ((unused, always_inline))
elf_machine_lazy_rel(struct link_map * map,struct r_scope_elem * scope[],Elf32_Addr l_addr,const Elf32_Rela * reloc,int skip_ifunc)307 elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
308 		      Elf32_Addr l_addr, const Elf32_Rela *reloc,
309 		      int skip_ifunc)
310 {
311   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
312   if (ELF32_R_TYPE (reloc->r_info) == R_68K_JMP_SLOT)
313     *reloc_addr += l_addr;
314   else
315     _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
316 }
317 
318 #endif /* RESOLVE_MAP */
319