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