Initialize Tizen 2.3
[external/prelink.git] / src / arch-mips.c
1 /* Copyright (C) 2006 CodeSourcery
2    Written by Richard Sandiford <richard@codesourcery.com>, 2006
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* GENERAL NOTES
19
20    The psABI defines R_MIPS_REL32 as A - EA + S, where the value of EA
21    depends on the symbol index.  If the index is less than DT_MIPS_GOTSYM,
22    EA is the symbol's st_value "plus displacement".  If the index is greater
23    than or equal to DT_MIPS_GOTSYM, EA is the original value of the
24    associated GOT entry.
25
26    However, glibc's dynamic linker implements a different definition.
27    If the index is less than DT_MIPS_GOTSYM, the dynamic linker adds the
28    symbol's st_value and the base address to the addend.  If the index
29    is greater than or equal to DT_MIPS_GOTSYM, the dynamic linker adds
30    the final symbol value to the addend.
31
32    MIPS GOTs are divided into three parts:
33
34      - Reserved entries (of which GNU objects have 2)
35      - Local entries
36      - Global entries
37
38    DT_MIPS_LOCAL_GOTNO gives the total number of reserved and local
39    entries.  The local entries all hold virtual addresses and the
40    dynamic linker will add the base address to each one.
41
42    Unlike most other architectures, the MIPS ABI does not use
43    relocations to initialize the global GOT entries.  Instead, global
44    GOT entry X is mapped to dynamic symbol DT_MIPS_GOTSYM + X, and there
45    are a total of DT_MIPS_SYMTABNO - DT_MIPS_GOTSYM global GOT entries.
46
47    The interpretation of a global GOT entry depends on the symbol entry
48    and the initial GOT contents.  The psABI lists the following cases:
49
50       st_shndx    st_type     st_value      initial GOT value
51       --------    -------     --------      -----------------
52    A: SHN_UNDEF   STT_FUNC    0             st_value (== 0) / QS
53    B: SHN_UNDEF   STT_FUNC    stub address  st_value / QS
54    C: SHN_UNDEF   all others  0             st_value (== 0) / QS
55    D: SHN_COMMON  any         alignment     0 / QS
56    E: all others  STT_FUNC    value         st_value / stub address
57    F: all others  all others  value         st_value
58
59    (wording slightly modified from the psABI table).  Here, QS denotes
60    Quickstart values.
61
62    The dynamic linker treats each case as follows:
63
64    - [A, B when not binding lazily, C, D, E when not binding lazily, F]
65      Resolve the symbol and store its value in the GOT.
66
67    - [B when binding lazily] Set the GOT entry to the st_value plus
68      the base address.
69
70    - [E when binding lazily] If the GOT entry is different from the st_value,
71      add the base addreess to the GOT entry.  Otherwise resolve the symbol
72      and store its value in the GOT (as for A, C, etc).
73
74    As the table shows, we can install Quickstart values for types A-D.
75    Installing Quickstart values for type F should be a no-op, because the
76    GOT should already hold the desired value.  Installing Quickstart values
77    for type E would either be a no-op (if the GOT entry already contains
78    st_value) or would lose the address of the lazy binding stub.  */
79
80 #include <config.h>
81 #include <assert.h>
82 #include <errno.h>
83 #include <fcntl.h>
84 #include <stdio.h>
85 #include <string.h>
86 #include <locale.h>
87 #include <error.h>
88 #include <argp.h>
89 #include <stdlib.h>
90
91 #include "prelink.h"
92 #include "layout.h"
93
94 /* The thread pointer points 0x7000 past the first static TLS block.  */
95 #define TLS_TP_OFFSET 0x7000
96
97 /* Dynamic thread vector pointers point 0x8000 past the start of each
98    TLS block.  */
99 #define TLS_DTV_OFFSET 0x8000
100
101 /* The number of reserved entries at the beginning of the GOT.
102    The dynamic linker points entry 0 to the resolver function
103    and entry 1 to the link_map.  */
104 #define RESERVED_GOTNO 2
105
106 /* A structure for iterating over local GOT entries.  */
107 struct mips_local_got_iterator {
108   /* The DSO containing the GOT.  */
109   DSO *dso;
110
111   /* The size of a GOT entry.  */
112   GElf_Word entry_size;
113
114   /* The index of the current GOT entry.  */
115   GElf_Word got_index;
116
117   /* A pointer to the current GOT entry.  */
118   unsigned char *got_entry;
119
120   /* True if we failed to read an entry correctly.  */
121   int failed;
122
123   /* Used internally to obtain GOT_ENTRY.  */
124   struct data_iterator got_iterator;
125 };
126
127 /* Set up LGI to iterate over DSO's local GOT.  The caller should use
128    mips_get_local_got_entry to read the first entry.  */
129
130 static inline void
131 mips_init_local_got_iterator (struct mips_local_got_iterator *lgi, DSO *dso)
132 {
133   lgi->dso = dso;
134   lgi->entry_size = gelf_fsize (dso->elf, ELF_T_WORD, 1, EV_CURRENT);
135   lgi->got_index = RESERVED_GOTNO - 1;
136   lgi->failed = 0;
137   init_data_iterator (&lgi->got_iterator, dso,
138                       dso->info[DT_PLTGOT]
139                       + (lgi->got_index + 1) * lgi->entry_size);
140 }
141
142 /* Return true if LGI has not reached the end of the GOT and if the next
143    entry can be accessed.  When returning true, use LGI's fields to
144    describe the next entry.  */
145
146 static inline int
147 mips_get_local_got_entry (struct mips_local_got_iterator *lgi)
148 {
149   lgi->got_index++;
150   if (lgi->got_index >= lgi->dso->info_DT_MIPS_LOCAL_GOTNO)
151     return 0;
152
153   lgi->got_entry = get_data_from_iterator (&lgi->got_iterator,
154                                            lgi->entry_size);
155   if (lgi->got_entry == NULL)
156     {
157       error (0, 0, "%s: Malformed local GOT\n", lgi->dso->filename);
158       lgi->failed = 1;
159       return 0;
160     }
161
162   return 1;
163 }
164
165 /* A structure for iterating over global GOT entries.  */
166 struct mips_global_got_iterator {
167   /* The DSO containing the GOT.  */
168   DSO *dso;
169
170   /* The size of a GOT entry.  */
171   GElf_Word entry_size;
172
173   /* The virtual address of the current GOT entry.  */
174   GElf_Addr got_addr;
175
176   /* The index of the associated entry in the dynamic symbol table.  */
177   GElf_Word sym_index;
178
179   /* A pointer to the current GOT entry.  */
180   unsigned char *got_entry;
181
182   /* The symbol associated with the current GOT entry.  */
183   GElf_Sym sym;
184
185   /* True if we failed to read an entry correctly.  */
186   int failed;
187
188   /* Used internally to obtain GOT_ENTRY and SYM.  */
189   struct data_iterator got_iterator;
190   struct data_iterator sym_iterator;
191 };
192
193 /* Set up GGI to iterate over DSO's global GOT.  The caller should use
194    mips_get_global_got_entry to read the first entry.  */
195
196 static inline void
197 mips_init_global_got_iterator (struct mips_global_got_iterator *ggi, DSO *dso)
198 {
199   GElf_Word sym_size;
200
201   ggi->dso = dso;
202   ggi->entry_size = gelf_fsize (dso->elf, ELF_T_WORD, 1, EV_CURRENT);
203   ggi->got_addr = (dso->info[DT_PLTGOT]
204                    + (dso->info_DT_MIPS_LOCAL_GOTNO - 1) * ggi->entry_size);
205   ggi->sym_index = dso->info_DT_MIPS_GOTSYM - 1;
206   ggi->failed = 0;
207
208   sym_size = gelf_fsize (dso->elf, ELF_T_SYM, 1, EV_CURRENT);
209   init_data_iterator (&ggi->got_iterator, dso,
210                       ggi->got_addr + ggi->entry_size);
211   init_data_iterator (&ggi->sym_iterator, dso,
212                       dso->info[DT_SYMTAB] + (ggi->sym_index + 1) * sym_size);
213 }
214
215 /* Return true if GGI has not reached the end of the GOT and if the next
216    entry can be accessed.  When returning true, use GGI's fields to
217    describe the next entry.  */
218
219 static inline int
220 mips_get_global_got_entry (struct mips_global_got_iterator *ggi)
221 {
222   ggi->sym_index++;
223   ggi->got_addr += ggi->entry_size;
224   if (ggi->sym_index >= ggi->dso->info_DT_MIPS_SYMTABNO)
225     return 0;
226
227   ggi->got_entry = get_data_from_iterator (&ggi->got_iterator,
228                                            ggi->entry_size);
229   if (ggi->got_entry == NULL
230       || !get_sym_from_iterator (&ggi->sym_iterator, &ggi->sym))
231     {
232       error (0, 0, "%s: Malformed global GOT\n", ggi->dso->filename);
233       ggi->failed = 1;
234       return 0;
235     }
236
237   return 1;
238 }
239
240 static int
241 mips_arch_adjust (DSO *dso, GElf_Addr start, GElf_Addr adjust)
242 {
243   struct mips_local_got_iterator lgi;
244   struct mips_global_got_iterator ggi;
245   GElf_Addr value;
246
247   if (dso->info[DT_PLTGOT] == 0)
248     return 0;
249
250   /* Adjust every local GOT entry by ADJUST.  Every adjustment moves
251      the code and data, so we do not need to check START here.  */
252   mips_init_local_got_iterator (&lgi, dso);
253   while (mips_get_local_got_entry (&lgi))
254     {
255       value = buf_read_une32 (dso, lgi.got_entry);
256       buf_write_ne32 (dso, lgi.got_entry, value + adjust);
257     }
258
259   /* Adjust every global GOT entry.  Referring to the table above:
260
261      For [A, B, C]: Adjust the GOT entry if it contains st_value
262      and if the symbol's value will be adjusted.
263
264      For [D]: Do nothing.  SHN_COMMON entries never need adjusting.
265
266      For [E, F]: Adjust the GOT entry if it does not contain st_value
267      -- in other words, if it is a type E entry that points to a lazy
268      binding stub -- or if the symbol's value will also be adjusted.  */
269   mips_init_global_got_iterator (&ggi, dso);
270   while (mips_get_global_got_entry (&ggi))
271     {
272       value = buf_read_une32 (dso, ggi.got_entry);
273       if (ggi.sym.st_shndx != SHN_COMMON
274           && value >= start
275           && (value == ggi.sym.st_value
276               ? adjust_symbol_p (dso, &ggi.sym)
277               : ggi.sym.st_shndx != SHN_UNDEF))
278         buf_write_ne32 (dso, ggi.got_entry, value + adjust);
279     }
280
281   return lgi.failed || ggi.failed;
282 }
283
284 static int
285 mips_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
286                  GElf_Addr adjust)
287 {
288   switch (dyn->d_tag)
289     {
290     case DT_MIPS_TIME_STAMP:
291     case DT_MIPS_ICHECKSUM:
292     case DT_MIPS_IVERSION:
293     case DT_MIPS_CONFLICT:
294     case DT_MIPS_CONFLICTNO:
295     case DT_MIPS_LIBLIST:
296     case DT_MIPS_LIBLISTNO:
297       error (0, 0, "%s: File contains QuickStart information", dso->filename);
298       return 1;
299
300     case DT_MIPS_BASE_ADDRESS:
301     case DT_MIPS_RLD_MAP:
302     case DT_MIPS_OPTIONS:
303       if (dyn->d_un.d_ptr >= start)
304         dyn->d_un.d_ptr += adjust;
305       return 1;
306
307     case DT_MIPS_LOCAL_GOTNO:
308     case DT_MIPS_UNREFEXTNO:
309     case DT_MIPS_SYMTABNO:
310     case DT_MIPS_HIPAGENO:
311     case DT_MIPS_GOTSYM:
312       /* We don't change the layout of the GOT or symbol table.  */
313       return 1;
314
315     case DT_MIPS_RLD_VERSION:
316     case DT_MIPS_FLAGS:
317       /* We don't change these properties.  */
318       return 1;
319     }
320   return 0;
321 }
322
323 /* Read the addend for a relocation in DSO.  If RELA is nonnull,
324    use its r_addend, otherwise read a 32-bit in-place addend from
325    address R_OFFSET.  */
326
327 static inline uint32_t
328 mips_read_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela)
329 {
330   return rela ? rela->r_addend : read_une32 (dso, r_offset);
331 }
332
333 /* Like mips_read_addend, but change the addend to VALUE.  */
334
335 static inline void
336 mips_write_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela,
337                    uint32_t value)
338 {
339   if (rela)
340     rela->r_addend = (int32_t) value;
341   else
342     write_ne32 (dso, r_offset, value);
343 }
344
345 /* There is a relocation of type R_INFO against address R_OFFSET in DSO.
346    Adjust it so that virtual addresses >= START are increased by ADJUST
347    If the relocation is in a RELA section, RELA points to the relocation,
348    otherwise it is null.  */
349
350 static int
351 mips_adjust_reloc (DSO *dso, GElf_Addr r_offset, GElf_Xword r_info,
352                    GElf_Addr start, GElf_Addr adjust, GElf_Rela *rela)
353 {
354   GElf_Addr value;
355   GElf_Word r_sym;
356
357   if (GELF_R_TYPE (r_info) == R_MIPS_REL32)
358     {
359       r_sym = GELF_R_SYM (r_info);
360       if (r_sym < dso->info_DT_MIPS_GOTSYM)
361         {
362           /* glibc's dynamic linker adds the symbol's st_value and the
363              base address to the addend.  It therefore treats all symbols
364              as being relative, even if they would normally be considered
365              absolute.  For example, the special null symbol should always
366              have the value zero, even when the base address is nonzero,
367              but R_MIPS_REL32 relocations against the null symbol must
368              nevertheles be adjusted as if that symbol were relative.
369              The same would apply to SHN_ABS symbols too.
370
371              Thus the result of the relocation calculation must always
372              be adjusted by ADJUST.  (We do not need to check START because
373              every adjustment requested by the caller will affect all
374              legitimate local relocation values.)  This means that we
375              should add ADJUST to the addend if and only if the symbol's
376              value is not being adjusted.
377
378              In general, we can only check whether a symbol's value is
379              being adjusted by reading its entry in the dynamic symbol
380              table and then querying adjust_symbol_p.  However, this
381              generality is fortunately not needed.  Modern versions
382              of binutils will never generate R_MIPS_REL32 relocations
383              against symbols in the range [1, DT_MIPS_GOTSYM), so we
384              only need to handle relocations against the null symbol.  */
385           if (r_sym != 0)
386             {
387               error (0, 0, "%s: The prelinker does not support R_MIPS_REL32"
388                      " relocs against local symbols", dso->filename);
389               return 1;
390             }
391           value = mips_read_addend (dso, r_offset, rela);
392           mips_write_addend (dso, r_offset, rela, value + adjust);
393         }
394     }
395   return 0;
396 }
397
398 static int
399 mips_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start, GElf_Addr adjust)
400 {
401   return mips_adjust_reloc (dso, rel->r_offset, rel->r_info,
402                             start, adjust, NULL);
403 }
404
405 static int
406 mips_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start, GElf_Addr adjust)
407 {
408   return mips_adjust_reloc (dso, rela->r_offset, rela->r_info,
409                             start, adjust, rela);
410 }
411
412 /* Calculate relocation RELA as A + VALUE and store the result in DSO.  */
413
414 static void
415 mips_prelink_32bit_reloc (DSO *dso, GElf_Rela *rela, GElf_Addr value)
416 {
417   assert (rela != NULL);
418   write_ne32 (dso, rela->r_offset, value + rela->r_addend);
419 }
420
421 /* There is a relocation of type R_INFO against address R_OFFSET in DSO.
422    Prelink the relocation field, using INFO to look up symbol values.
423    If the relocation is in a RELA section, RELA points to the relocation,
424    otherwise it is null.  */
425
426 static int
427 mips_prelink_reloc (struct prelink_info *info, GElf_Addr r_offset,
428                     GElf_Xword r_info, GElf_Rela *rela)
429 {
430   DSO *dso;
431   GElf_Addr value;
432   GElf_Word r_sym;
433   int r_type;
434
435   dso = info->dso;
436   r_sym = GELF_R_SYM (r_info);
437   r_type = GELF_R_TYPE (r_info);
438   switch (r_type)
439     {
440     case R_MIPS_NONE:
441       break;
442
443     case R_MIPS_REL32:
444       /* An in-place R_MIPS_REL32 relocation against symbol 0 needs no
445          adjustment.  */
446       if (rela != NULL || GELF_R_SYM (r_info) != 0)
447         {
448           value = info->resolve (info, r_sym, r_type);
449           mips_prelink_32bit_reloc (dso, rela, value);
450         }
451       break;
452
453     case R_MIPS_GLOB_DAT:
454       write_ne32 (dso, r_offset, info->resolve (info, r_sym, r_type));
455       break;
456
457     case R_MIPS_TLS_DTPMOD32:
458       if (dso->ehdr.e_type == ET_EXEC)
459         {
460           error (0, 0, "%s: R_MIPS_TLS_DTPMOD32 reloc in executable?",
461                  dso->filename);
462           return 1;
463         }
464       /* These relocations will be resolved using a conflict.  We need
465          not change the field value here.  */
466       break;
467
468     case R_MIPS_TLS_DTPREL32:
469       value = info->resolve (info, r_sym, r_type);
470       mips_prelink_32bit_reloc (dso, rela, value - TLS_DTV_OFFSET);
471       break;
472
473     case R_MIPS_TLS_TPREL32:
474       /* Relocations in a shared library will be resolved using a conflict.
475          We need not change the relocation field here.  */
476       if (dso->ehdr.e_type == ET_EXEC)
477         {
478           value = info->resolve (info, r_sym, r_type);
479           value += info->resolvetls->offset - TLS_TP_OFFSET;
480           mips_prelink_32bit_reloc (dso, rela, value);
481         }
482       break;
483
484     default:
485       error (0, 0, "%s: Unknown MIPS relocation type %d",
486              dso->filename, (int) GELF_R_TYPE (r_info));
487       return 1;
488     }
489   return 0;
490 }
491
492 static int
493 mips_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
494 {
495   DSO *dso;
496
497   /* Convert R_MIPS_REL32 relocations against global symbols into
498      R_MIPS_GLOB_DAT if the addend is zero.  */
499   dso = info->dso;
500   if (GELF_R_TYPE (rel->r_info) == R_MIPS_REL32
501       && GELF_R_SYM (rel->r_info) >= dso->info_DT_MIPS_GOTSYM
502       && read_une32 (dso, rel->r_offset) == 0)
503     {
504       rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_MIPS_GLOB_DAT);
505       write_ne32 (dso, rel->r_offset,
506                   info->resolve (info, GELF_R_SYM (rel->r_info),
507                                  GELF_R_TYPE (rel->r_info)));
508       return 2;
509     }
510   return mips_prelink_reloc (info, rel->r_offset, rel->r_info, NULL);
511 }
512
513 static int
514 mips_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
515                    GElf_Addr relaaddr)
516 {
517   return mips_prelink_reloc (info, rela->r_offset, rela->r_info, rela);
518 }
519
520 /* CONFLICT is a conflict returned by prelink_conflict for a symbol
521    belonging to DSO.  Set *TLS_OUT to the associated TLS information.
522    Return 1 on failure.  */
523
524 static int
525 mips_get_tls (DSO *dso, struct prelink_conflict *conflict,
526               struct prelink_tls **tls_out)
527 {
528   if (conflict->reloc_class != RTYPE_CLASS_TLS
529       || conflict->lookup.tls == NULL)
530     {
531       error (0, 0, "%s: R_MIPS_TLS not resolving to STT_TLS symbol",
532              dso->filename);
533       return 1;
534     }
535
536   *tls_out = conflict->lookup.tls;
537   return 0;
538 }
539
540 /* There is a relocation of type R_INFO against address R_OFFSET in DSO.
541    See if the relocation field must be adjusted by a conflict when DSO
542    is used in the context described by INFO.  Add a conflict entry if so.
543    If the relocation is in a RELA section, RELA points to the relocation,
544    otherwise it is null.  */
545
546 static int
547 mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info,
548                              GElf_Addr r_offset, GElf_Xword r_info,
549                              GElf_Rela *rela)
550 {
551   GElf_Addr value;
552   struct prelink_conflict *conflict;
553   struct prelink_tls *tls = NULL;
554   GElf_Rela *entry;
555
556   if (info->dso == dso)
557     return 0;
558
559   conflict = prelink_conflict (info, GELF_R_SYM (r_info),
560                                GELF_R_TYPE (r_info));
561   if (conflict == NULL)
562     {
563       switch (GELF_R_TYPE (r_info))
564         {
565         case R_MIPS_TLS_DTPMOD32:
566         case R_MIPS_TLS_TPREL32:
567           tls = info->curtls;
568           if (tls == NULL)
569             return 0;
570           /* A relocation against symbol 0.  A shared library cannot
571              know what the final module IDs or TP-relative offsets are,
572              so the executable must always have a conflict for them.  */
573           value = 0;
574           break;
575         default:
576           return 0;
577         }
578     }
579   else if (conflict->ifunc)
580     {
581       error (0, 0, "%s: STT_GNU_IFUNC not handled on MIPS yet",
582              dso->filename);
583       return 1;
584     }
585   else
586     {
587       /* DTPREL32 relocations just involve the symbol value; no other
588          TLS information is needed.  Ignore conflicts created from a
589          lookup of type RTYPE_CLASS_TLS if no real conflict exists.  */
590       if (GELF_R_TYPE (r_info) == R_MIPS_TLS_DTPREL32
591           && conflict->lookup.tls == conflict->conflict.tls
592           && conflict->lookupval == conflict->conflictval)
593         return 0;
594
595       value = conflict_lookup_value (conflict);
596     }
597   /* VALUE now contains the final symbol value.  Change it to the
598      value we want to store at R_OFFSET.  */
599   switch (GELF_R_TYPE (r_info))
600     {
601     case R_MIPS_REL32:
602       value += mips_read_addend (dso, r_offset, rela);
603       break;
604
605     case R_MIPS_GLOB_DAT:
606       break;
607
608     case R_MIPS_TLS_DTPMOD32:
609       if (conflict != NULL && mips_get_tls (dso, conflict, &tls) == 1)
610         return 1;
611       value = tls->modid;
612       break;
613
614     case R_MIPS_TLS_DTPREL32:
615       value += mips_read_addend (dso, r_offset, rela) - TLS_DTV_OFFSET;
616       break;
617
618     case R_MIPS_TLS_TPREL32:
619       if (conflict != NULL && mips_get_tls (dso, conflict, &tls) == 1)
620         return 1;
621       value += (mips_read_addend (dso, r_offset, rela)
622                 + tls->offset - TLS_TP_OFFSET);
623       break;
624
625     default:
626       error (0, 0, "%s: Unknown MIPS relocation type %d", dso->filename,
627              (int) GELF_R_TYPE (r_info));
628       return 1;
629     }
630   /* Create and initialize a conflict entry.  */
631   entry = prelink_conflict_add_rela (info);
632   if (entry == NULL)
633     return 1;
634   entry->r_addend = (int32_t) value;
635   entry->r_offset = r_offset;
636   entry->r_info = GELF_R_INFO (0, R_MIPS_REL32);
637   return 0;
638 }
639
640 static int
641 mips_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
642                            GElf_Rel *rel, GElf_Addr reladdr)
643 {
644   return mips_prelink_conflict_reloc (dso, info, rel->r_offset,
645                                       rel->r_info, NULL);
646 }
647
648 static int
649 mips_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
650                             GElf_Rela *rela, GElf_Addr relaaddr)
651 {
652   return mips_prelink_conflict_reloc (dso, info, rela->r_offset,
653                                       rela->r_info, rela);
654 }
655
656 static int
657 mips_arch_prelink_conflict (DSO *dso, struct prelink_info *info)
658 {
659   struct mips_global_got_iterator ggi;
660   GElf_Addr value;
661   struct prelink_conflict *conflict;
662   GElf_Rela *entry;
663
664   if (info->dso == dso || dso->info[DT_PLTGOT] == 0)
665     return 0;
666
667   /* Add a conflict for every global GOT entry that does not hold the
668      right value, either because of a conflict, or because the DSO has
669      a lazy binding stub for a symbol that it also defines.  */
670   mips_init_global_got_iterator (&ggi, dso);
671   while (mips_get_global_got_entry (&ggi))
672     {
673       conflict = prelink_conflict (info, ggi.sym_index, R_MIPS_REL32);
674       if (conflict != NULL)
675         value = conflict_lookup_value (conflict);
676       else if (ggi.sym.st_shndx != SHN_UNDEF
677                && ggi.sym.st_shndx != SHN_COMMON)
678         value = ggi.sym.st_value;
679       else
680         continue;
681       if (buf_read_une32 (dso, ggi.got_entry) != value)
682         {
683           entry = prelink_conflict_add_rela (info);
684           if (entry == NULL)
685             return 1;
686           entry->r_addend = (int32_t) value;
687           entry->r_offset = ggi.got_addr;
688           entry->r_info = GELF_R_INFO (0, R_MIPS_REL32);
689         }
690     }
691
692   return ggi.failed;
693 }
694
695 static int
696 mips_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
697                           char *buf, GElf_Addr dest_addr)
698 {
699   switch (GELF_R_TYPE (rela->r_info))
700     {
701     case R_MIPS_REL32:
702       buf_write_ne32 (info->dso, buf, rela->r_addend);
703       break;
704
705     default:
706       abort ();
707     }
708   return 0;
709 }
710
711 /* BUF points to a 32-bit field in DSO that is subject to relocation.
712    If the relocation is in a RELA section, RELA points to the relocation,
713    otherwise it is null.  Add the addend to ADJUSTMENT and install the
714    result.  */
715
716 static inline void
717 mips_apply_adjustment (DSO *dso, GElf_Rela *rela, char *buf,
718                        GElf_Addr adjustment)
719 {
720   if (rela)
721     adjustment += rela->r_addend;
722   else
723     adjustment += buf_read_une32 (dso, buf);
724   buf_write_ne32 (dso, buf, adjustment);
725 }
726
727 static int
728 mips_apply_reloc (struct prelink_info *info, GElf_Xword r_info,
729                   GElf_Rela *rela, char *buf)
730 {
731   DSO *dso;
732
733   dso = info->dso;
734   switch (GELF_R_TYPE (r_info))
735     {
736     case R_MIPS_NONE:
737       break;
738
739     case R_MIPS_REL32:
740       mips_apply_adjustment (dso, rela, buf,
741                              info->resolve (info, GELF_R_SYM (r_info),
742                                             GELF_R_TYPE (r_info)));
743       break;
744
745     default:
746       return 1;
747     }
748   return 0;
749 }
750
751 static int
752 mips_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
753 {
754   return mips_apply_reloc (info, rel->r_info, NULL, buf);
755 }
756
757 static int
758 mips_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
759 {
760   return mips_apply_reloc (info, rela->r_info, rela, buf);
761 }
762
763 static int
764 mips_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
765 {
766   rela->r_offset = rel->r_offset;
767   rela->r_info = rel->r_info;
768   switch (GELF_R_TYPE (rel->r_info))
769     {
770     case R_MIPS_REL32:
771     case R_MIPS_TLS_DTPREL32:
772     case R_MIPS_TLS_TPREL32:
773       /* These relocations have an in-place addend.  */
774       rela->r_addend = (int32_t) read_une32 (dso, rel->r_offset);
775       break;
776
777     case R_MIPS_NONE:
778     case R_MIPS_GLOB_DAT:
779     case R_MIPS_TLS_DTPMOD32:
780       /* These relocations have no addend.  */
781       rela->r_addend = 0;
782       break;
783
784     default:
785       error (0, 0, "%s: Unknown MIPS relocation type %d", dso->filename,
786              (int) GELF_R_TYPE (rel->r_info));
787       return 1;
788     }
789   return 0;
790 }
791
792 static int
793 mips_rela_to_rel (DSO *dso, GElf_Rela *rela, GElf_Rel *rel)
794 {
795   rel->r_offset = rela->r_offset;
796   rel->r_info = rela->r_info;
797   switch (GELF_R_TYPE (rela->r_info))
798     {
799     case R_MIPS_NONE:
800       break;
801
802     case R_MIPS_REL32:
803     case R_MIPS_TLS_DTPREL32:
804     case R_MIPS_TLS_TPREL32:
805       /* These relocations have an in-place addend.  */
806       write_ne32 (dso, rela->r_offset, rela->r_addend);
807       break;
808
809     case R_MIPS_GLOB_DAT:
810     case R_MIPS_TLS_DTPMOD32:
811       /* These relocations have no addend.  */
812       write_ne32 (dso, rela->r_offset, 0);
813       break;
814
815     default:
816       error (0, 0, "%s: Unknown MIPS relocation type %d", dso->filename,
817              (int) GELF_R_TYPE (rela->r_info));
818       return 1;
819     }
820   return 0;
821 }
822
823 static int
824 mips_need_rel_to_rela (DSO *dso, int first, int last)
825 {
826   Elf_Data *data;
827   Elf_Scn *scn;
828   Elf32_Rel *rel, *relend;
829   int n;
830
831   for (n = first; n <= last; n++)
832     {
833       data = NULL;
834       scn = dso->scn[n];
835       while ((data = elf_getdata (scn, data)) != NULL)
836         {
837           rel = (Elf32_Rel *) data->d_buf;
838           relend = rel + data->d_size / sizeof (Elf32_Rel);
839           for (; rel < relend; rel++)
840             switch (ELF32_R_TYPE (rel->r_info))
841               {
842               case R_MIPS_NONE:
843                 break;
844
845               case R_MIPS_REL32:
846                 /* The SVR4 definition was designed to allow exactly the
847                    sort of prelinking we want to do here, in combination
848                    with Quickstart.  Unfortunately, glibc's definition
849                    makes it impossible for relocations against anything
850                    other than the null symbol.  We get around this for
851                    zero addends by using a R_MIPS_GLOB_DAT relocation
852                    instead, where R_MIPS_GLOB_DAT is a GNU extension
853                    added specifically for this purpose.  */
854                 if (ELF32_R_SYM (rel->r_info) != 0
855                     && (ELF32_R_SYM (rel->r_info) < dso->info_DT_MIPS_GOTSYM
856                         || read_une32 (dso, rel->r_offset) != 0))
857                   return 1;
858                 break;
859
860               case R_MIPS_GLOB_DAT:
861                 /* This relocation has no addend.  */
862                 break;
863
864               case R_MIPS_TLS_DTPMOD32:
865                 /* The relocation will be resolved using a conflict.  */
866                 break;
867
868               case R_MIPS_TLS_DTPREL32:
869                 /* We can prelink these fields, and the addend is relative
870                    to the symbol value.  A RELA entry is needed.  */
871                 return 1;
872
873               case R_MIPS_TLS_TPREL32:
874                 /* Relocations in shared libraries will be resolved by a
875                    conflict.  Relocations in executables will not, and the
876                    addend is relative to the symbol value.  */
877                 if (dso->ehdr.e_type == ET_EXEC)
878                   return 1;
879                 break;
880
881               default:
882                 error (0, 0, "%s: Unknown MIPS relocation type %d",
883                        dso->filename, (int) GELF_R_TYPE (rel->r_info));
884                 return 1;
885               }
886         }
887     }
888   return 0;
889 }
890
891 static int
892 mips_reloc_size (int reloc_type)
893 {
894   return 4;
895 }
896
897 static int
898 mips_reloc_class (int reloc_type)
899 {
900   switch (reloc_type)
901     {
902     case R_MIPS_TLS_DTPMOD32:
903     case R_MIPS_TLS_DTPREL32:
904     case R_MIPS_TLS_TPREL32:
905       return RTYPE_CLASS_TLS;
906     default:
907       /* MIPS lazy resolution stubs are local to the containing object,
908          so SHN_UNDEF symbols never participate in symbol lookup.  */
909       return RTYPE_CLASS_PLT;
910     }
911 }
912
913 static int
914 mips_arch_prelink (struct prelink_info *info)
915 {
916   struct mips_global_got_iterator ggi;
917   DSO *dso;
918   GElf_Addr value;
919
920   dso = info->dso;
921   if (dso->info[DT_PLTGOT] == 0)
922     return 0;
923
924   /* Install Quickstart values for all global GOT entries of type A-D
925      in the table above.  */
926   mips_init_global_got_iterator (&ggi, dso);
927   while (mips_get_global_got_entry (&ggi))
928     {
929       value = info->resolve (info, ggi.sym_index, R_MIPS_REL32);
930       if (ggi.sym.st_shndx == SHN_UNDEF
931           || ggi.sym.st_shndx == SHN_COMMON)
932         buf_write_ne32 (dso, ggi.got_entry, value);
933       else
934         {
935           /* Type E and F in the table above.  We cannot install Quickstart
936              values for type E, but we should never need to in executables,
937              because an executable should not use lazy binding stubs for
938              symbols it defines itself.  Although we could in theory just
939              discard any such stub address, it goes against the principle
940              that prelinking should be reversible.
941
942              When type E entries occur in shared libraries, we can fix
943              them up using conflicts.
944
945              Type F entries should never need a Quickstart value -- the
946              current value should already be correct.  However, the conflict
947              code will cope correctly with malformed type F entries in
948              shared libraries, so we only complain about executables here.  */
949           if (dso->ehdr.e_type == ET_EXEC
950               && value != buf_read_une32 (dso, ggi.got_entry))
951             {
952               error (0, 0, "%s: The global GOT entries for defined symbols"
953                      " do not match their st_values\n", dso->filename);
954               return 1;
955             }
956         }
957     }
958   return ggi.failed;
959 }
960
961 static int
962 mips_arch_undo_prelink (DSO *dso)
963 {
964   struct mips_global_got_iterator ggi;
965
966   if (dso->info[DT_PLTGOT] == 0)
967     return 0;
968
969   mips_init_global_got_iterator (&ggi, dso);
970   while (mips_get_global_got_entry (&ggi))
971     if (ggi.sym.st_shndx == SHN_UNDEF)
972       /* Types A-C in the table above.  */
973       buf_write_ne32 (dso, ggi.got_entry, ggi.sym.st_value);
974     else if (ggi.sym.st_shndx == SHN_COMMON)
975       /* Type D in the table above.  */
976       buf_write_ne32 (dso, ggi.got_entry, 0);
977   return ggi.failed;
978 }
979
980 static int
981 mips_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr)
982 {
983   /* Convert R_MIPS_GLOB_DAT relocations back into R_MIPS_REL32
984      relocations.  Ideally we'd have some mechanism for recording
985      these changes in the undo section, but in the absence of that,
986      it's better to assume that the original relocation was
987      R_MIPS_REL32; R_MIPS_GLOB_DAT was added specifically for the
988      prelinker and shouldn't be used in non-prelinked binaries.  */
989   if (GELF_R_TYPE (rel->r_info) == R_MIPS_GLOB_DAT)
990     {
991       write_ne32 (dso, rel->r_offset, 0);
992       rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_MIPS_REL32);
993       return 2;
994     }
995   return 0;
996 }
997
998 PL_ARCH = {
999   .name = "MIPS",
1000   .class = ELFCLASS32,
1001   .machine = EM_MIPS,
1002   .max_reloc_size = 4,
1003   .dynamic_linker = "/lib/ld.so.1",
1004   /* MIPS does not use COPY relocs or jump slots.  Pick a value outside
1005      the ELF32_R_TYPE range.  */
1006   .R_COPY = ~0U,
1007   .R_JMP_SLOT = ~0U,
1008   /* R_MIPS_REL32 relocations against symbol 0 do act as relative relocs,
1009      but those against other symbols don't.  */
1010   .R_RELATIVE = ~0U,
1011   .rtype_class_valid = RTYPE_CLASS_VALID,
1012   .arch_adjust = mips_arch_adjust,
1013   .adjust_dyn = mips_adjust_dyn,
1014   .adjust_rel = mips_adjust_rel,
1015   .adjust_rela = mips_adjust_rela,
1016   .prelink_rel = mips_prelink_rel,
1017   .prelink_rela = mips_prelink_rela,
1018   .prelink_conflict_rel = mips_prelink_conflict_rel,
1019   .prelink_conflict_rela = mips_prelink_conflict_rela,
1020   .arch_prelink_conflict = mips_arch_prelink_conflict,
1021   .apply_conflict_rela = mips_apply_conflict_rela,
1022   .apply_rel = mips_apply_rel,
1023   .apply_rela = mips_apply_rela,
1024   .rel_to_rela = mips_rel_to_rela,
1025   .rela_to_rel = mips_rela_to_rel,
1026   .need_rel_to_rela = mips_need_rel_to_rela,
1027   .reloc_size = mips_reloc_size,
1028   .reloc_class = mips_reloc_class,
1029   .arch_prelink = mips_arch_prelink,
1030   .arch_undo_prelink = mips_arch_undo_prelink,
1031   .undo_prelink_rel = mips_undo_prelink_rel,
1032   /* Although TASK_UNMAPPED_BASE is 0x2aaa8000, we leave some
1033      area so that mmap of /etc/ld.so.cache and ld.so's malloc
1034      does not take some library's VA slot.
1035      Also, if this guard area isn't too small, typically
1036      even dlopened libraries will get the slots they desire.  */
1037   .mmap_base = 0x2c000000,
1038   .mmap_end =  0x3c000000,
1039   .max_page_size = 0x10000,
1040   .page_size = 0x1000
1041 };