1 /* Machine-dependent ELF dynamic relocation inline functions.  m68k version.
2    Copyright (C) 1996-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 #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 	| See if we were run as a command with the executable file\n\
146 	| name as an extra leading argument.\n\
147 	" PCREL_OP ("move.l", "_dl_skip_args", "%d0", "%d0", "%pc") "\n\
148 	| Pop the original argument count\n\
149 	move.l (%sp)+, %d1\n\
150 	| Subtract _dl_skip_args from it.\n\
151 	sub.l %d0, %d1\n\
152 	| Adjust the stack pointer to skip _dl_skip_args words.\n\
153 	lea (%sp, %d0*4), %sp\n\
154 	| Push back the modified argument count.\n\
155 	move.l %d1, -(%sp)\n\
156 	# Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\
157 	pea 8(%sp, %d1*4)\n\
158 	pea 8(%sp)\n\
159 	move.l %d1, -(%sp)\n\
160 	" PCREL_OP ("move.l", "_rtld_local", "-(%sp)", "%d0", "%pc") "\n\
161 	jbsr _dl_init\n\
162 	addq.l #8, %sp\n\
163 	addq.l #8, %sp\n\
164 	| Pass our finalizer function to the user in %a1.\n\
165 	" PCREL_OP ("lea", "_dl_fini", "%a1", "%a1", "%pc") "\n\
166 	| Initialize %fp with the stack pointer.\n\
167 	move.l %sp, %fp\n\
168 	| Jump to the user's entry point.\n\
169 	jmp (%a4)\n\
170 	.size _dl_start_user, . - _dl_start_user\n\
171 	.previous");
172 
173 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
174    TLS variable, so undefined references should not be allowed to
175    define the value.
176    ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
177    of the main executable's symbols, as for a COPY reloc.  */
178 #define elf_machine_type_class(type) \
179   ((((type) == R_68K_JMP_SLOT	     \
180      || (type) == R_68K_TLS_DTPMOD32 \
181      || (type) == R_68K_TLS_DTPREL32 \
182      || (type) == R_68K_TLS_TPREL32) * ELF_RTYPE_CLASS_PLT)	\
183    | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY))
184 
185 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
186 #define ELF_MACHINE_JMP_SLOT	R_68K_JMP_SLOT
187 
188 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)189 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
190 		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
191 		       const Elf32_Rela *reloc,
192 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
193 {
194   return *reloc_addr = value;
195 }
196 
197 /* Return the final value of a plt relocation.  On the m68k the JMP_SLOT
198    relocation ignores the addend.  */
199 static inline Elf32_Addr
elf_machine_plt_value(struct link_map * map,const Elf32_Rela * reloc,Elf32_Addr value)200 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
201 		       Elf32_Addr value)
202 {
203   return value;
204 }
205 
206 /* Names of the architecture-specific auditing callback functions.  */
207 #define ARCH_LA_PLTENTER m68k_gnu_pltenter
208 #define ARCH_LA_PLTEXIT m68k_gnu_pltexit
209 
210 #endif /* !dl_machine_h */
211 
212 #ifdef RESOLVE_MAP
213 
214 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
215    MAP is the object containing the reloc.  */
216 
217 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)218 elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
219 		  const Elf32_Rela *reloc, const Elf32_Sym *sym,
220 		  const struct r_found_version *version,
221 		  void *const reloc_addr_arg, int skip_ifunc)
222 {
223   Elf32_Addr *const reloc_addr = reloc_addr_arg;
224   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
225 
226   if (__builtin_expect (r_type == R_68K_RELATIVE, 0))
227     *reloc_addr = map->l_addr + reloc->r_addend;
228   else
229     {
230       const Elf32_Sym *const refsym = sym;
231       struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
232 					      r_type);
233       Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
234 
235       switch (r_type)
236 	{
237 	case R_68K_COPY:
238 	  if (sym == NULL)
239 	    /* This can happen in trace mode if an object could not be
240 	       found.  */
241 	    break;
242 	  if (sym->st_size > refsym->st_size
243 	      || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
244 	    {
245 	      const char *strtab;
246 
247 	      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
248 	      _dl_error_printf ("\
249 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
250 				RTLD_PROGNAME, strtab + refsym->st_name);
251 	    }
252 	  memcpy (reloc_addr_arg, (void *) value,
253 		  MIN (sym->st_size, refsym->st_size));
254 	  break;
255 	case R_68K_GLOB_DAT:
256 	case R_68K_JMP_SLOT:
257 	  *reloc_addr = value;
258 	  break;
259 	case R_68K_8:
260 	  *(char *) reloc_addr = value + reloc->r_addend;
261 	  break;
262 	case R_68K_16:
263 	  *(short *) reloc_addr = value + reloc->r_addend;
264 	  break;
265 	case R_68K_32:
266 	  *reloc_addr = value + reloc->r_addend;
267 	  break;
268 	case R_68K_PC8:
269 	  *(char *) reloc_addr
270 	    = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
271 	  break;
272 	case R_68K_PC16:
273 	  *(short *) reloc_addr
274 	    = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
275 	  break;
276 	case R_68K_PC32:
277 	  *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
278 	  break;
279 #ifndef RTLD_BOOTSTRAP
280 	case R_68K_TLS_DTPMOD32:
281 	  /* Get the information from the link map returned by the
282 	     resolv function.  */
283 	  if (sym_map != NULL)
284 	    *reloc_addr = sym_map->l_tls_modid;
285 	  break;
286 	case R_68K_TLS_DTPREL32:
287 	  if (sym != NULL)
288 	    *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
289 	  break;
290 	case R_68K_TLS_TPREL32:
291 	  if (sym != NULL)
292 	    {
293 	      CHECK_STATIC_TLS (map, sym_map);
294 	      *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
295 	    }
296 	  break;
297 #endif /* !RTLD_BOOTSTRAP */
298 	case R_68K_NONE:		/* Alright, Wilbur.  */
299 	  break;
300 	default:
301 	  _dl_reloc_bad_type (map, r_type, 0);
302 	  break;
303 	}
304     }
305 }
306 
307 static inline void __attribute__ ((unused, always_inline))
elf_machine_rela_relative(Elf32_Addr l_addr,const Elf32_Rela * reloc,void * const reloc_addr_arg)308 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
309 			   void *const reloc_addr_arg)
310 {
311   Elf32_Addr *const reloc_addr = reloc_addr_arg;
312   *reloc_addr = l_addr + reloc->r_addend;
313 }
314 
315 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)316 elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
317 		      Elf32_Addr l_addr, const Elf32_Rela *reloc,
318 		      int skip_ifunc)
319 {
320   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
321   if (ELF32_R_TYPE (reloc->r_info) == R_68K_JMP_SLOT)
322     *reloc_addr += l_addr;
323   else
324     _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
325 }
326 
327 #endif /* RESOLVE_MAP */
328