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