Content for TLS_IE_GOT not written to .got.
[external/binutils.git] / bfd / arc-got.h
1 /* ARC-specific support for 32-bit ELF
2    Copyright (C) 1994-2016 Free Software Foundation, Inc.
3    Contributed by Cupertino Miranda (cmiranda@synopsys.com).
4
5    This file is part of BFD, the Binary File Descriptor library.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21
22 #ifndef ARC_GOT_H
23 #define ARC_GOT_H
24
25 enum tls_type_e
26 {
27   GOT_UNKNOWN = 0,
28   GOT_NORMAL,
29   GOT_TLS_GD,
30   GOT_TLS_IE,
31   GOT_TLS_LE
32 };
33
34 enum tls_got_entries
35 {
36   TLS_GOT_NONE = 0,
37   TLS_GOT_MOD,
38   TLS_GOT_OFF,
39   TLS_GOT_MOD_AND_OFF
40 };
41
42 struct got_entry
43 {
44   struct got_entry *next;
45   enum tls_type_e type;
46   bfd_vma offset;
47   bfd_boolean processed;
48   bfd_boolean created_dyn_relocation;
49   enum tls_got_entries existing_entries;
50 };
51
52 static struct got_entry **
53 arc_get_local_got_ents (bfd * abfd)
54 {
55   static struct got_entry **local_got_ents = NULL;
56
57   if (local_got_ents == NULL)
58     {
59       size_t       size;
60       Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
61
62       size = symtab_hdr->sh_info * sizeof (bfd_vma);
63       local_got_ents = (struct got_entry **)
64         bfd_alloc (abfd, sizeof (struct got_entry *) * size);
65       if (local_got_ents == NULL)
66         return FALSE;
67
68       memset (local_got_ents, 0, sizeof (struct got_entry *) * size);
69       elf_local_got_ents (abfd) = local_got_ents;
70     }
71
72   return local_got_ents;
73 }
74
75 static struct got_entry *
76 got_entry_for_type (struct got_entry **list,
77                     enum tls_type_e type)
78 {
79   struct got_entry **p = list;
80
81   while (*p != NULL)
82     {
83       if ((*p)->type == type)
84         return *p;
85       p = &((*p)->next);
86     }
87   return NULL;
88 }
89
90 static void
91 new_got_entry_to_list (struct got_entry **list,
92                        enum tls_type_e type,
93                        bfd_vma offset,
94                        enum tls_got_entries existing_entries)
95 {
96   /* Find list end.  Avoid having multiple entries of the same
97      type.  */
98   struct got_entry **p = list;
99   struct got_entry *entry;
100
101   while (*p != NULL)
102     {
103       if ((*p)->type == type)
104         return;
105       p = &((*p)->next);
106     }
107
108   entry = (struct got_entry *) xmalloc (sizeof (struct got_entry));
109
110   entry->type = type;
111   entry->offset = offset;
112   entry->next = NULL;
113   entry->processed = FALSE;
114   entry->created_dyn_relocation = FALSE;
115   entry->existing_entries = existing_entries;
116
117   ARC_DEBUG ("New GOT got entry added to list: "
118              "type: %d, offset: %ld, existing_entries: %d\n",
119              type, (long) offset, existing_entries);
120
121   /* Add the entry to the end of the list.  */
122   *p = entry;
123 }
124
125 static enum tls_type_e
126 tls_type_for_reloc (reloc_howto_type *howto)
127 {
128   enum tls_type_e ret = GOT_UNKNOWN;
129
130   if (is_reloc_for_GOT (howto))
131     return GOT_NORMAL;
132
133   switch (howto->type)
134     {
135     case R_ARC_TLS_GD_GOT:
136       ret = GOT_TLS_GD;
137       break;
138     case R_ARC_TLS_IE_GOT:
139       ret = GOT_TLS_IE;
140       break;
141     case R_ARC_TLS_LE_32:
142       ret = GOT_TLS_LE;
143       break;
144     default:
145       ret = GOT_UNKNOWN;
146       break;
147     }
148
149   return ret;
150 };
151
152 static struct got_entry **
153 get_got_entry_list_for_symbol (bfd *abfd,
154                                unsigned long r_symndx,
155                                struct elf_link_hash_entry *h)
156 {
157   if (h != NULL)
158     {
159       return &h->got.glist;
160     }
161   else
162     {
163       struct got_entry **local_got_ents
164         = arc_get_local_got_ents (abfd);
165       return &local_got_ents[r_symndx];
166     }
167 }
168
169
170 static enum tls_type_e
171 arc_got_entry_type_for_reloc (reloc_howto_type *howto)
172 {
173   enum tls_type_e type = GOT_UNKNOWN;
174
175   if (is_reloc_for_GOT (howto))
176     return  GOT_NORMAL;
177
178   if (is_reloc_for_TLS (howto))
179     {
180       switch (howto->type)
181         {
182           case R_ARC_TLS_GD_GOT:
183             type = GOT_TLS_GD;
184             break;
185           case R_ARC_TLS_IE_GOT:
186             type = GOT_TLS_IE;
187             break;
188           default:
189             break;
190         }
191     }
192   return type;
193 }
194
195 #define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H)        \
196   htab->s##SECNAME->size;                                               \
197   {                                                                     \
198     if (COND_FOR_RELOC)                                                 \
199       {                                                                 \
200         htab->srel##SECNAME->size += sizeof (Elf32_External_Rela);      \
201           ARC_DEBUG ("arc_info: Added reloc space in "                  \
202                      #SECNAME " section at " __FILE__                   \
203                      ":%d for symbol %s\n",                             \
204                      __LINE__, name_for_global_symbol (H));             \
205       }                                                                 \
206     if (H)                                                              \
207       if (h->dynindx == -1 && !h->forced_local)                         \
208         if (! bfd_elf_link_record_dynamic_symbol (info, H))             \
209           return FALSE;                                                 \
210      htab->s##SECNAME->size += 4;                                       \
211    }                                                                    \
212
213 static bfd_boolean
214 arc_fill_got_info_for_reloc (enum tls_type_e type,
215                              struct got_entry **list,
216                              struct bfd_link_info *  info,
217                              struct elf_link_hash_entry *h)
218 {
219   struct elf_link_hash_table *htab = elf_hash_table (info);
220
221   if (got_entry_for_type (list, type) != NULL)
222     return TRUE;
223
224   switch (type)
225     {
226       case GOT_NORMAL:
227         {
228           bfd_vma offset
229             = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info)
230                                                  || h != NULL, h);
231           new_got_entry_to_list (list, type, offset, TLS_GOT_NONE);
232         }
233         break;
234
235
236       case GOT_TLS_GD:
237         {
238           bfd_vma offset
239             = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
240           bfd_vma ATTRIBUTE_UNUSED notneeded
241             = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
242           new_got_entry_to_list (list, type, offset, TLS_GOT_MOD_AND_OFF);
243         }
244         break;
245       case GOT_TLS_IE:
246       case GOT_TLS_LE:
247         {
248           bfd_vma offset
249             = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
250           new_got_entry_to_list (list, type, offset, TLS_GOT_OFF);
251         }
252         break;
253
254       default:
255         return FALSE;
256         break;
257     }
258   return TRUE;
259 }
260
261
262 static bfd_vma
263 relocate_fix_got_relocs_for_got_info (struct got_entry **          list_p,
264                                       enum tls_type_e              type,
265                                       struct bfd_link_info *       info,
266                                       bfd *                        output_bfd,
267                                       unsigned long                r_symndx,
268                                       Elf_Internal_Sym *           local_syms,
269                                       asection **                  local_sections,
270                                       struct elf_link_hash_entry * h,
271                                       struct arc_relocation_data * reloc_data)
272 {
273   struct elf_link_hash_table *htab = elf_hash_table (info);
274   struct got_entry *entry = NULL;
275
276   if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE)
277     return 0;
278
279   entry = got_entry_for_type (list_p, type);
280   BFD_ASSERT (entry);
281
282   if (h == NULL
283       || (! elf_hash_table (info)->dynamic_sections_created
284           || (bfd_link_pic (info)
285               && SYMBOL_REFERENCES_LOCAL (info, h))))
286     {
287       const char ATTRIBUTE_UNUSED *symbol_name;
288       static const char local_name[] = "(local)";
289       asection *tls_sec = NULL;
290       bfd_vma sym_value = 0;
291
292       if (h != NULL)
293         {
294           // TODO: This should not be here.
295           reloc_data->sym_value = h->root.u.def.value;
296           reloc_data->sym_section = h->root.u.def.section;
297
298           sym_value = h->root.u.def.value
299             + h->root.u.def.section->output_section->vma
300             + h->root.u.def.section->output_offset;
301
302           tls_sec = elf_hash_table (info)->tls_sec;
303
304           symbol_name = h->root.root.string;
305         }
306       else
307         {
308           Elf_Internal_Sym *sym = local_syms + r_symndx;
309           asection *sec = local_sections[r_symndx];
310
311           sym_value = sym->st_value
312             + sec->output_section->vma
313             + sec->output_offset;
314
315           tls_sec = elf_hash_table (info)->tls_sec;
316
317           symbol_name = local_name;
318         }
319
320
321       if (entry && entry->processed == FALSE)
322         {
323           switch (entry->type)
324             {
325             case GOT_TLS_GD:
326               {
327                 BFD_ASSERT (tls_sec && tls_sec->output_section);
328                 bfd_vma sec_vma = tls_sec->output_section->vma;
329
330                 bfd_put_32 (output_bfd,
331                             sym_value - sec_vma,
332                             htab->sgot->contents + entry->offset
333                             + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
334                                ? 4 : 0));
335
336                 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
337                            "@ %lx, for symbol %s\n",
338                            (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
339                             "GOT_TLS_IE"),
340                            (long) (sym_value - sec_vma),
341                            (long) (htab->sgot->output_section->vma
342                               + htab->sgot->output_offset->vma
343                               + entry->offset
344                               + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
345                                  ? 4 : 0)),
346                            symbol_name);
347               }
348               break;
349
350             case GOT_TLS_IE:
351               {
352                 BFD_ASSERT (tls_sec && tls_sec->output_section);
353                 bfd_vma ATTRIBUTE_UNUSED sec_vma
354                   = tls_sec->output_section->vma;
355
356                 bfd_put_32 (output_bfd,
357                             sym_value - sec_vma,
358                             htab->sgot->contents + entry->offset
359                             + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
360                                ? 4 : 0));
361
362                 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
363                            "@ %p, for symbol %s\n",
364                            (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
365                             "GOT_TLS_IE"),
366                            (long) (sym_value - sec_vma),
367                            (long) (htab->sgot->output_section->vma
368                               + htab->sgot->output_offset->vma
369                               + entry->offset
370                               + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
371                                  ? 4 : 0)),
372                            symbol_name);
373               }
374               break;
375
376             case GOT_NORMAL:
377               {
378                 bfd_vma sec_vma
379                   = reloc_data->sym_section->output_section->vma
380                   + reloc_data->sym_section->output_offset;
381
382                 if (h != NULL
383                     && h->root.type == bfd_link_hash_undefweak)
384                   ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
385                              "@ %#08lx for sym %s in got offset %#lx "
386                              "(is undefweak)\n",
387                              (long) (htab->sgot->output_section->vma
388                                      + htab->sgot->output_offset
389                                      + entry->offset),
390                              symbol_name,
391                              (long) entry->offset);
392                 else
393                   {
394                     bfd_put_32 (output_bfd,
395                                 reloc_data->sym_value + sec_vma,
396                                 htab->sgot->contents + entry->offset);
397                     ARC_DEBUG ("arc_info: PATCHED: %#08lx "
398                                "@ %#08lx for sym %s in got offset %#lx\n",
399                                (long) (reloc_data->sym_value + sec_vma),
400                                (long) (htab->sgot->output_section->vma
401                                        + htab->sgot->output_offset + entry->offset),
402                                symbol_name,
403                                (long) entry->offset);
404                   }
405               }
406               break;
407             default:
408               BFD_ASSERT (0);
409               break;
410             }
411           entry->processed = TRUE;
412         }
413     }
414
415   return entry->offset;
416 }
417
418 static void
419 create_got_dynrelocs_for_single_entry (struct got_entry *list,
420                                        bfd *output_bfd,
421                                        struct bfd_link_info *  info,
422                                        struct elf_link_hash_entry *h)
423 {
424   if (list == NULL)
425     return;
426
427   bfd_vma got_offset = list->offset;
428
429   if (list->type == GOT_NORMAL
430       && list->created_dyn_relocation == FALSE)
431     {
432       if (bfd_link_pic (info)
433           && h != NULL
434               && (info->symbolic || h->dynindx == -1)
435               && h->def_regular)
436         {
437           ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
438         }
439       /* Do not fully understand the side effects of this condition.
440          The relocation space might still being reserved.  Perhaps
441          I should clear its value.  */
442       else if (h != NULL && h->dynindx != -1)
443         {
444           ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0);
445         }
446       list->created_dyn_relocation = TRUE;
447     }
448   else if (list->existing_entries != TLS_GOT_NONE
449            && list->created_dyn_relocation == FALSE)
450     {
451        /* TODO TLS: This is not called for local symbols.
452           In order to correctly implement TLS, this should also
453           be called for all local symbols with tls got entries.
454           Should be moved to relocate_section in order to make it
455           work for local symbols.  */
456       struct elf_link_hash_table *htab = elf_hash_table (info);
457       enum tls_got_entries e = list->existing_entries;
458
459       BFD_ASSERT (list->type != GOT_TLS_GD
460               || list->existing_entries == TLS_GOT_MOD_AND_OFF);
461
462       bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx;
463
464       if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
465         {
466               ADD_RELA (output_bfd, got, got_offset, dynindx,
467                     R_ARC_TLS_DTPMOD, 0);
468               ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
469 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n",
470                          list->type,
471                          (long) got_offset,
472                          (long) (htab->sgot->output_section->vma
473                                  + htab->sgot->output_offset + got_offset),
474                          (long) dynindx);
475         }
476
477       if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
478         {
479           bfd_vma addend = 0;
480           if (list->type == GOT_TLS_IE)
481             addend = bfd_get_32 (output_bfd,
482                                  htab->sgot->contents + got_offset);
483
484           ADD_RELA (output_bfd, got,
485                     got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
486                     dynindx,
487                     (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF
488                                               : R_ARC_TLS_DTPOFF),
489                     addend);
490
491           ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
492 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
493                      list->type,
494                      (long) got_offset,
495                      (long) (htab->sgot->output_section->vma
496                              + htab->sgot->output_offset + got_offset),
497                      (long) dynindx, (long) addend);
498         }
499       list->created_dyn_relocation = TRUE;
500     }
501 }
502
503 static void
504 create_got_dynrelocs_for_got_info (struct got_entry **list_p,
505                                    bfd *output_bfd,
506                                    struct bfd_link_info *  info,
507                                    struct elf_link_hash_entry *h)
508 {
509   if (list_p == NULL)
510     return;
511
512   struct got_entry *list = *list_p;
513   /* Traverse the list of got entries for this symbol.  */
514   while (list)
515     {
516       create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
517       list = list->next;
518     }
519 }
520
521 #undef ADD_SYMBOL_REF_SEC_AND_RELOC
522
523 #endif /* ARC_GOT_H */