(elf_machine_rela): Mention program name in warning message.
[kopensolaris-gnu/glibc.git] / sysdeps / mips / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  MIPS version.
2    Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #ifndef dl_machine_h
22 #define dl_machine_h
23
24 #define ELF_MACHINE_NAME "MIPS"
25
26 #include <assert.h>
27 #include <entry.h>
28
29 #ifndef ENTRY_POINT
30 #error ENTRY_POINT needs to be defined for MIPS.
31 #endif
32
33 #ifndef _RTLD_PROLOGUE
34 #ifdef __STDC__
35 #define _RTLD_PROLOGUE(entry) "\n\t.globl " #entry \
36                               "\n\t.ent " #entry \
37                               "\n\t" #entry ":\n\t"
38 #else
39 #define _RTLD_PROLOGUE(entry) "\n\t.globl entry\n\t.ent entry\n\t entry:\n\t"
40 #endif
41 #endif
42
43 #ifndef _RTLD_EPILOGUE
44 #ifdef __STDC__
45 #define _RTLD_EPILOGUE(entry) "\t.end " #entry "\n"
46 #else
47 #define _RTLD_EPILOGUE(entry) "\t.end entry\n"
48 #endif
49 #endif
50
51 /* I have no idea what I am doing. */
52 #define ELF_MACHINE_RELOC_NOPLT                 -1
53 #define elf_machine_lookup_noplt_p(type)        (1)
54 #define elf_machine_lookup_noexec_p(type)       (0)
55
56 /* Translate a processor specific dynamic tag to the index
57    in l_info array.  */
58 #define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)
59
60 #if 0
61 /* We may need 64k alignment. */
62 #define ELF_MACHINE_ALIGN_MASK 0xffff
63 #endif
64
65 /*
66  * MIPS libraries are usually linked to a non-zero base address.  We
67  * subtrace the base address from the address where we map the object
68  * to.  This results in more efficient address space usage.
69  */
70 #if 0
71 #define MAP_BASE_ADDR(l) ((l)->l_info[DT_MIPS(BASE_ADDRESS)] ? \
72                           (l)->l_info[DT_MIPS(BASE_ADDRESS)]->d_un.d_ptr : 0)
73 #else
74 #define MAP_BASE_ADDR(l) 0x5ffe0000
75 #endif
76
77 /* If there is a DT_MIPS_RLD_MAP entry in the dynamic section, fill it in
78    with the run-time address of the r_debug structure  */
79 #define ELF_MACHINE_DEBUG_SETUP(l,r) \
80 do { if ((l)->l_info[DT_MIPS (RLD_MAP)]) \
81        *(ElfW(Addr) *)((l)->l_info[DT_MIPS (RLD_MAP)]->d_un.d_ptr) = \
82        (ElfW(Addr)) (r); \
83    } while (0)
84
85 /* Return nonzero iff E_MACHINE is compatible with the running host.  */
86 static inline int __attribute__ ((unused))
87 elf_machine_matches_host (ElfW(Half) e_machine)
88 {
89   switch (e_machine)
90     {
91     case EM_MIPS:
92     case EM_MIPS_RS4_BE:
93       return 1;
94     default:
95       return 0;
96     }
97 }
98
99 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
100 +   first element of the GOT.  This must be inlined in a function which
101 +   uses global data.  */
102 +static inline ElfW(Addr)
103 +elf_machine_dynamic (void)
104 +{
105 +  register ElfW(Addr) gp asm ("$28");
106 +  return * (ElfW(Addr) *) (gp - 0x7ff0);
107 +}
108 +
109 static inline ElfW(Addr) *
110 elf_mips_got_from_gpreg (ElfW(Addr) gpreg)
111 {
112   /* FIXME: the offset of gp from GOT may be system-dependent. */
113   return (ElfW(Addr) *) (gpreg - 0x7ff0);
114 }
115
116 /* Return the run-time address of the _GLOBAL_OFFSET_TABLE_.
117    Must be inlined in a function which uses global data.  */
118 static inline ElfW(Addr) *
119 elf_machine_got (void)
120 {
121   ElfW(Addr) gp;
122
123   __asm__ __volatile__("move %0, $28\n\t" : "=r" (gp));
124   return elf_mips_got_from_gpreg (gp);
125 }
126
127
128 /* Return the run-time load address of the shared object.  */
129 static inline ElfW(Addr)
130 elf_machine_load_address (void)
131 {
132   ElfW(Addr) addr;
133   asm ("        .set noreorder\n"
134        "        la %0, here\n"
135        "        bltzal $0, here\n"
136        "        nop\n"
137        "here:   subu %0, $31, %0\n"
138        "        .set reorder\n"
139        :        "=r" (addr)
140        :        /* No inputs */
141        :        "$31");
142   return addr;
143 }
144
145 /* The MSB of got[1] of a gnu object is set to identify gnu objects. */
146 #define ELF_MIPS_GNU_GOT1_MASK 0x80000000
147
148 /* Relocate GOT. */
149 static inline void
150 elf_machine_got_rel (struct link_map *map, int lazy)
151 {
152   ElfW(Addr) *got;
153   ElfW(Sym) *sym;
154   int i, n;
155   struct link_map **scope;
156   const char *strtab
157     = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
158
159 #define RESOLVE_GOTSYM(sym) \
160     ({ \
161       const ElfW(Sym) *ref = sym; \
162       ElfW(Addr) sym_loadaddr; \
163       sym_loadaddr = _dl_lookup_symbol (strtab + sym->st_name, &ref, scope, \
164                                         map->l_name, ELF_MACHINE_RELOC_NOPLT);\
165       (ref)? sym_loadaddr + ref->st_value: 0; \
166     })
167
168   got = (ElfW(Addr) *) ((void *) map->l_addr
169                         + map->l_info[DT_PLTGOT]->d_un.d_ptr);
170
171   /* got[0] is reserved. got[1] is also reserved for the dynamic object
172      generated by gnu ld. Skip these reserved entries from relocation.  */
173   i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2: 1;
174   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
175   /* Add the run-time display to all local got entries. */
176   while (i < n)
177     got[i++] += map->l_addr;
178
179   /* Set scope.  */
180   scope = _dl_object_relocation_scope (map);
181
182   /* Handle global got entries. */
183   got += n;
184   sym = (ElfW(Sym) *) ((void *) map->l_addr
185                        + map->l_info[DT_SYMTAB]->d_un.d_ptr);
186   sym += map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
187   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val
188        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);
189
190   while (i--)
191     {
192       if (sym->st_shndx == SHN_UNDEF)
193         {
194           if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC)
195             {
196               if (sym->st_value && lazy)
197                 *got = sym->st_value + map->l_addr;
198               else
199                 *got = RESOLVE_GOTSYM (sym);
200             }
201           else /* if (*got == 0 || *got == QS) */
202             *got = RESOLVE_GOTSYM (sym);
203         }
204       else if (sym->st_shndx == SHN_COMMON)
205         *got = RESOLVE_GOTSYM (sym);
206       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
207                && *got != sym->st_value
208                && lazy)
209         *got += map->l_addr;
210       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)
211         {
212           if (sym->st_other == 0)
213             *got += map->l_addr;
214         }
215       else
216         *got = RESOLVE_GOTSYM (sym);
217
218       got++;
219       sym++;
220     }
221
222 #undef RESOLVE_GOTSYM
223   *_dl_global_scope_end = NULL;
224
225   return;
226 }
227
228 /* Set up the loaded object described by L so its stub function
229    will jump to the on-demand fixup code in dl-runtime.c.  */
230
231 static inline int
232 elf_machine_runtime_setup (struct link_map *l, int lazy)
233 {
234   ElfW(Addr) *got;
235   extern void _dl_runtime_resolve (ElfW(Word));
236   extern int _dl_mips_gnu_objects;
237
238 #ifdef RTLD_BOOTSTRAP
239     {
240       return lazy;
241     }
242 #endif
243   if (lazy)
244     {
245       /* The GOT entries for functions have not yet been filled in.
246          Their initial contents will arrange when called to put an
247          offset into the .dynsym section in t8, the return address
248          in t7 and then jump to _GLOBAL_OFFSET_TABLE[0].  */
249       got = (ElfW(Addr) *) ((void *) l->l_addr
250                             + l->l_info[DT_PLTGOT]->d_un.d_ptr);
251
252       /* This function will get called to fix up the GOT entry indicated by
253          the register t8, and then jump to the resolved address.  */
254       got[0] = (ElfW(Addr)) &_dl_runtime_resolve;
255
256       /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB
257          of got[1] of a gnu object is set to identify gnu objects.
258          Where we can store l for non gnu objects? XXX  */
259       if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)
260         got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK);
261       else
262         _dl_mips_gnu_objects = 0;
263     }
264
265   /* Relocate global offset table.  */
266   elf_machine_got_rel (l, lazy);
267
268   return lazy;
269 }
270
271 /* Get link_map for this object.  */
272 static inline struct link_map *
273 elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
274 {
275   extern int _dl_mips_gnu_objects;
276
277   /* got[1] is reserved to keep its link map address for the shared
278      object generated by gnu linker. If all are such object, we can
279      find link map from current GPREG simply. If not so, get link map
280      for callers object containing STUB_PC.  */
281
282   if (_dl_mips_gnu_objects)
283     {
284       ElfW(Addr) *got = elf_mips_got_from_gpreg (gpreg);
285       ElfW(Word) g1;
286
287       g1 = ((ElfW(Word) *) got)[1];
288
289       if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0)
290         return (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK);
291     }
292
293     {
294       struct link_map *l = _dl_loaded;
295       struct link_map *ret = 0;
296       ElfW(Addr) candidate = 0;
297
298       while (l)
299         {
300           ElfW(Addr) base = 0;
301           const ElfW(Phdr) *p = l->l_phdr;
302           ElfW(Half) this, nent = l->l_phnum;
303
304           /* Get the base. */
305           for (this = 0; this < nent; this++)
306             if (p[this].p_type == PT_LOAD)
307               {
308                 base = p[this].p_vaddr + l->l_addr;
309                 break;
310               }
311           if (! base)
312             {
313               l = l->l_next;
314               continue;
315             }
316
317           /* Find closest link base addr. */
318           if ((base < stub_pc) && (candidate < base))
319             {
320               candidate = base;
321               ret = l;
322             }
323           l = l->l_next;
324         }
325       if (candidate && ret && (candidate < stub_pc))
326         return ret;
327       else if (!candidate)
328         return _dl_loaded;
329     }
330
331   _dl_signal_error (0, NULL, "cannot find runtime link map");
332   return NULL;
333 }
334
335 /* Mips has no PLT but define elf_machine_relplt to be elf_machine_rel. */
336 #define elf_machine_relplt elf_machine_rel
337
338 /* Define mips specific runtime resolver. The function __dl_runtime_resolve
339    is called from assembler function _dl_runtime_resolve which converts
340    special argument registers t7 ($15) and t8 ($24):
341      t7  address to return to the caller of the function
342      t8  index for this function symbol in .dynsym
343    to usual c arguments.  */
344
345 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                                        \
346 /* The flag _dl_mips_gnu_objects is set if all dynamic objects are            \
347    generated by the gnu linker. */                                            \
348 int _dl_mips_gnu_objects = 1;                                                 \
349                                                                               \
350 /* This is called from assembly stubs below which the compiler can't see.  */ \
351 static ElfW(Addr)                                                             \
352 __dl_runtime_resolve (ElfW(Word), ElfW(Word), ElfW(Addr), ElfW(Addr))         \
353                   __attribute__ ((unused));                                   \
354                                                                               \
355 static ElfW(Addr)                                                             \
356 __dl_runtime_resolve (ElfW(Word) sym_index,                                   \
357                       ElfW(Word) return_address,                              \
358                       ElfW(Addr) old_gpreg,                                   \
359                       ElfW(Addr) stub_pc)                                     \
360 {                                                                             \
361   struct link_map *l = elf_machine_runtime_link_map (old_gpreg, stub_pc);     \
362   const ElfW(Sym) *const symtab                                               \
363     = (const ElfW(Sym) *) (l->l_addr + l->l_info[DT_SYMTAB]->d_un.d_ptr);     \
364   const char *strtab                                                          \
365     = (void *) (l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);                \
366   const ElfW(Addr) *got                                                       \
367     = (const ElfW(Addr) *) (l->l_addr + l->l_info[DT_PLTGOT]->d_un.d_ptr);    \
368   const ElfW(Word) local_gotno                                                \
369     = (const ElfW(Word)) l->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;        \
370   const ElfW(Word) gotsym                                                     \
371     = (const ElfW(Word)) l->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;             \
372   const ElfW(Sym) *definer;                                                   \
373   ElfW(Addr) loadbase;                                                        \
374   ElfW(Addr) funcaddr;                                                        \
375   struct link_map **scope;                                                    \
376                                                                               \
377   /* Look up the symbol's run-time value.  */                                 \
378   scope = _dl_object_relocation_scope (l);                                    \
379   definer = &symtab[sym_index];                                               \
380                                                                               \
381   loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer,          \
382                                 scope, l->l_name, ELF_MACHINE_RELOC_NOPLT);   \
383                                                                               \
384   *_dl_global_scope_end = NULL;                                               \
385                                                                               \
386   /* Apply the relocation with that value.  */                                \
387   funcaddr = loadbase + definer->st_value;                                    \
388   *(got + local_gotno + sym_index - gotsym) = funcaddr;                       \
389                                                                               \
390   return funcaddr;                                                            \
391 }                                                                             \
392                                                                               \
393 asm ("\n                                                                      \
394         .text\n                                                               \
395         .align  2\n                                                           \
396         .globl  _dl_runtime_resolve\n                                         \
397         .type   _dl_runtime_resolve,@function\n                               \
398         .ent    _dl_runtime_resolve\n                                         \
399 _dl_runtime_resolve:\n                                                        \
400         .set noreorder\n                                                      \
401         # Save slot call pc.\n                                                \
402         move    $3, $31\n                                                     \
403         # Modify t9 ($25) so as to point .cpload instruction.\n               \
404         addu    $25,8\n                                                       \
405         # Compute GP.\n                                                       \
406         .cpload $25\n                                                         \
407         .set reorder\n                                                        \
408         # Save slot call pc.\n                                                \
409         move    $2, $31\n                                                     \
410         # Save arguments and sp value in stack.\n                             \
411         subu    $29, 40\n                                                     \
412         .cprestore 32\n                                                       \
413         sw      $15, 36($29)\n                                                \
414         sw      $4, 12($29)\n                                                 \
415         sw      $5, 16($29)\n                                                 \
416         sw      $6, 20($29)\n                                                 \
417         sw      $7, 24($29)\n                                                 \
418         sw      $16, 28($29)\n                                                \
419         move    $16, $29\n                                                    \
420         move    $4, $24\n                                                     \
421         move    $5, $15\n                                                     \
422         move    $6, $3\n                                                      \
423         move    $7, $2\n                                                      \
424         jal     __dl_runtime_resolve\n                                        \
425         move    $29, $16\n                                                    \
426         lw      $31, 36($29)\n                                                \
427         lw      $4, 12($29)\n                                                 \
428         lw      $5, 16($29)\n                                                 \
429         lw      $6, 20($29)\n                                                 \
430         lw      $7, 24($29)\n                                                 \
431         lw      $16, 28($29)\n                                                \
432         addu    $29, 40\n                                                     \
433         move    $25, $2\n                                                     \
434         jr      $25\n                                                         \
435         .end    _dl_runtime_resolve\n                                         \
436 ");
437
438 /* Mask identifying addresses reserved for the user program,
439    where the dynamic linker should not map anything.  */
440 #define ELF_MACHINE_USER_ADDRESS_MASK   0x80000000UL
441
442
443
444 /* Initial entry point code for the dynamic linker.
445    The C function `_dl_start' is the real entry point;
446    its return value is the user program's entry point.
447    Note how we have to be careful about two things:
448
449    1) That we allocate a minimal stack of 24 bytes for
450       every function call, the MIPS ABI states that even
451       if all arguments are passed in registers the procedure
452       called can use the 16 byte area pointed to by $sp
453       when it is called to store away the arguments passed
454       to it.
455
456    2) That under Linux the entry is named __start
457       and not just plain _start.  */
458
459 #define RTLD_START asm ("\
460         .text\n"\
461 _RTLD_PROLOGUE(ENTRY_POINT)\
462 "       .globl _dl_start_user\n\
463         .set noreorder\n\
464         bltzal $0, 0f\n\
465         nop\n\
466 0:      .cpload $31\n\
467         .set reorder\n\
468         # i386 ABI book says that the first entry of GOT holds\n\
469         # the address of the dynamic structure. Though MIPS ABI\n\
470         # doesn't say nothing about this, I emulate this here.\n\
471         la $4, _DYNAMIC\n\
472         sw $4, -0x7ff0($28)\n\
473         move $4, $29\n\
474         subu $29, 16\n\
475         jal _dl_start\n\
476         addiu $29, 16\n\
477         # Get the value of label '_dl_start_user' in t9 ($25).\n\
478         la $25, _dl_start_user\n\
479 _dl_start_user:\n\
480         .set noreorder\n\
481         .cpload $25\n\
482         .set reorder\n\
483         move $16, $28\n\
484         # Save the user entry point address in saved register.\n\
485         move $17, $2\n\
486         # See if we were run as a command with the executable file\n\
487         # name as an extra leading argument.\n\
488         lw $2, _dl_skip_args\n\
489         beq $2, $0, 1f\n\
490         # Load the original argument count.\n\
491         lw $4, 0($29)\n\
492         # Subtract _dl_skip_args from it.\n\
493         subu $4, $2\n\
494         # Adjust the stack pointer to skip _dl_skip_args words.\n\
495         sll $2,2\n\
496         addu $29, $2\n\
497         # Save back the modified argument count.\n\
498         sw $4, 0($29)\n\
499         # Get _dl_default_scope[2] as argument in _dl_init_next call below.\n\
500 1:      la $2, _dl_default_scope\n\
501         lw $4, 8($2)\n\
502         # Call _dl_init_next to return the address of an initializer\n\
503         # function to run.\n\
504         subu $29, 16\n\
505         jal _dl_init_next\n\
506         addiu $29, 16\n\
507         move $28, $16\n\
508         # Check for zero return,  when out of initializers.\n\
509         beq $2, $0, 2f\n\
510         # Call the shared object initializer function.\n\
511         move $25, $2\n\
512         lw $4, 0($29)\n\
513         lw $5, 4($29)\n\
514         lw $6, 8($29)\n\
515         lw $7, 12($29)\n\
516         jalr $25\n\
517         move $28, $16\n\
518         # Loop to call _dl_init_next for the next initializer.\n\
519         b 1b\n\
520 2:      # Clear the startup flag.  Assumes 32 bit ints.\n\
521         sw $0, _dl_starting_up\n\
522         # Pass our finalizer function to the user in ra.\n\
523         la $31, _dl_fini\n\
524         # Jump to the user entry point.\n\
525         move $25, $17\n\
526         lw $4, 0($29)\n\
527         lw $5, 4($29)\n\
528         lw $6, 8($29)\n\
529         lw $7, 12($29)\n\
530         jr $25\n"\
531 _RTLD_EPILOGUE(ENTRY_POINT)\
532 );
533
534 /* The MIPS never uses Elfxx_Rela relocations.  */
535 #define ELF_MACHINE_NO_RELA 1
536
537 #endif /* !dl_machine_h */
538
539 #ifdef RESOLVE
540
541 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
542    MAP is the object containing the reloc.  */
543
544 static inline void
545 elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
546                  const ElfW(Sym) *sym, const struct r_found_version *version)
547 {
548   ElfW(Addr) *const reloc_addr = (void *) (map->l_addr + reloc->r_offset);
549   ElfW(Addr) loadbase;
550   ElfW(Addr) undo __attribute__ ((unused));
551
552   switch (ELFW(R_TYPE) (reloc->r_info))
553     {
554     case R_MIPS_REL32:
555       {
556         ElfW(Addr) undo = 0;
557
558         if (ELFW(ST_BIND) (sym->st_info) == STB_LOCAL
559             && (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION
560                 || ELFW(ST_TYPE) (sym->st_info) == STT_NOTYPE))
561           {
562             *reloc_addr += map->l_addr;
563             break;
564           }
565 #ifndef RTLD_BOOTSTRAP
566         /* This is defined in rtld.c, but nowhere in the static libc.a;
567            make the reference weak so static programs can still link.  This
568            declaration cannot be done when compiling rtld.c (i.e.  #ifdef
569            RTLD_BOOTSTRAP) because rtld.c contains the common defn for
570            _dl_rtld_map, which is incompatible with a weak decl in the same
571            file.  */
572         weak_extern (_dl_rtld_map);
573         if (map == &_dl_rtld_map)
574           /* Undo the relocation done here during bootstrapping.  Now we will
575              relocate it anew, possibly using a binding found in the user
576              program or a loaded library rather than the dynamic linker's
577              built-in definitions used while loading those libraries.  */
578           undo = map->l_addr + sym->st_value;
579 #endif
580           loadbase = RESOLVE (&sym, version, 0);
581           *reloc_addr += (sym ? (loadbase + sym->st_value) : 0) - undo;
582         }
583       break;
584     case R_MIPS_NONE:           /* Alright, Wilbur.  */
585       break;
586     default:
587       assert (! "unexpected dynamic reloc type");
588       break;
589     }
590 }
591
592 static inline void
593 elf_machine_lazy_rel (struct link_map *map, const ElfW(Rel) *reloc)
594 {
595   /* Do nothing.  */
596 }
597
598 #endif /* RESOLVE */