aboutsummaryrefslogtreecommitdiff
path: root/ld/ldelfgen.c
blob: c0568f169ff69e32abf01c4b3c7b4c92e07f7a7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/* Emulation code used by all ELF targets.
   Copyright (C) 1991-2020 Free Software Foundation, Inc.

   This file is part of the GNU Binutils.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

#include "sysdep.h"
#include "bfd.h"
#include "bfdlink.h"
#include "ctf-api.h"
#include "ld.h"
#include "ldmain.h"
#include "ldmisc.h"
#include "ldexp.h"
#include "ldlang.h"
#include "elf-bfd.h"
#include "ldelfgen.h"

void
ldelf_map_segments (bfd_boolean need_layout)
{
  int tries = 10;

  do
    {
      lang_relax_sections (need_layout);
      need_layout = FALSE;

      if (link_info.output_bfd->xvec->flavour == bfd_target_elf_flavour
	  && !bfd_link_relocatable (&link_info))
	{
	  bfd_size_type phdr_size;

	  phdr_size = elf_program_header_size (link_info.output_bfd);
	  /* If we don't have user supplied phdrs, throw away any
	     previous linker generated program headers.  */
	  if (lang_phdr_list == NULL)
	    elf_seg_map (link_info.output_bfd) = NULL;
	  if (!_bfd_elf_map_sections_to_segments (link_info.output_bfd,
						  &link_info))
	    einfo (_("%F%P: map sections to segments failed: %E\n"));

	  if (phdr_size != elf_program_header_size (link_info.output_bfd))
	    {
	      if (tries > 6)
		/* The first few times we allow any change to
		   phdr_size .  */
		need_layout = TRUE;
	      else if (phdr_size
		       < elf_program_header_size (link_info.output_bfd))
		/* After that we only allow the size to grow.  */
		need_layout = TRUE;
	      else
		elf_program_header_size (link_info.output_bfd) = phdr_size;
	    }
	}
    }
  while (need_layout && --tries);

  if (tries == 0)
    einfo (_("%F%P: looping in map_segments"));

  if (link_info.output_bfd->xvec->flavour == bfd_target_elf_flavour
      && lang_phdr_list == NULL)
    {
      /* If we don't have user supplied phdrs, strip zero-sized dynamic
	 sections and regenerate program headers.  */
      const struct elf_backend_data *bed
	= get_elf_backend_data (link_info.output_bfd);
      if (bed->elf_backend_strip_zero_sized_dynamic_sections
	  && !bed->elf_backend_strip_zero_sized_dynamic_sections
		(&link_info))
	  einfo (_("%F%P: failed to strip zero-sized dynamic sections"));
    }
}

/* We want to emit CTF early if and only if we are not targetting ELF with this
   invocation.  */

int
ldelf_emit_ctf_early (void)
{
  if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
    return 0;
  return 1;
}

/* Callbacks used to map from bfd types to libctf types, under libctf's
   control.  */

struct ctf_strsym_iter_cb_arg
{
  struct elf_sym_strtab *syms;
  bfd_size_type symcount;
  struct elf_strtab_hash *symstrtab;
  size_t next_i;
  size_t next_idx;
};

/* Return strings from the strtab to libctf, one by one.  Returns NULL when
   iteration is complete.  */

static const char *
ldelf_ctf_strtab_iter_cb (uint32_t *offset, void *arg_)
{
  bfd_size_type off;
  const char *ret;

  struct ctf_strsym_iter_cb_arg *arg =
    (struct ctf_strsym_iter_cb_arg *) arg_;

  /* There is no zeroth string.  */
  if (arg->next_i == 0)
    arg->next_i = 1;

  if (arg->next_i >= _bfd_elf_strtab_len (arg->symstrtab))
    {
      arg->next_i = 0;
      return NULL;
    }

  ret = _bfd_elf_strtab_str (arg->symstrtab, arg->next_i++, &off);
  *offset = off;

  /* If we've overflowed, we cannot share any further strings: the CTF
     format cannot encode strings with such high offsets.  */
  if (*offset != off)
    return NULL;

  return ret;
}

/* Return symbols from the symbol table to libctf, one by one.  We assume (and
   assert) that the symbols in the elf_link_hash_table are in strictly ascending
   order, and that none will be added in between existing ones.  Returns NULL
   when iteration is complete.  */

static struct ctf_link_sym *
ldelf_ctf_symbols_iter_cb (struct ctf_link_sym *dest,
					   void *arg_)
{
  struct ctf_strsym_iter_cb_arg *arg =
    (struct ctf_strsym_iter_cb_arg *) arg_;

  if (arg->next_i > arg->symcount)
    {
      arg->next_i = 0;
      arg->next_idx = 0;
      return NULL;
    }

  ASSERT (arg->syms[arg->next_i].dest_index == arg->next_idx);
  dest->st_name = _bfd_elf_strtab_str (arg->symstrtab, arg->next_i, NULL);
  dest->st_shndx = arg->syms[arg->next_i].sym.st_shndx;
  dest->st_type = ELF_ST_TYPE (arg->syms[arg->next_i].sym.st_info);
  dest->st_value = arg->syms[arg->next_i].sym.st_value;
  arg->next_i++;
  return dest;
}

void
ldelf_examine_strtab_for_ctf
  (struct ctf_file *ctf_output, struct elf_sym_strtab *syms,
   bfd_size_type symcount, struct elf_strtab_hash *symstrtab)
{
  struct ctf_strsym_iter_cb_arg args = { syms, symcount, symstrtab,
					  0, 0 };
   if (!ctf_output)
     return;

   if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
       && !bfd_link_relocatable (&link_info))
    {
      if (ctf_link_add_strtab (ctf_output, ldelf_ctf_strtab_iter_cb,
			       &args) < 0)
	einfo (_("%F%P: warning: CTF strtab association failed; strings will "
		 "not be shared: %s\n"),
	       ctf_errmsg (ctf_errno (ctf_output)));

      if (ctf_link_shuffle_syms (ctf_output, ldelf_ctf_symbols_iter_cb,
				 &args) < 0)
	einfo (_("%F%P: warning: CTF symbol shuffling failed; slight space "
		 "cost: %s\n"), ctf_errmsg (ctf_errno (ctf_output)));
    }
}