Coverage Report

Created: 2025-06-24 06:45

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