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