summaryrefslogtreecommitdiff
path: root/gold/target.cc
blob: 8a20ff050646a4258f49816f08274652dc612947 (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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
// target.cc -- target support for gold.

// Copyright (C) 2009-2023 Free Software Foundation, Inc.
// Written by Doug Kwan <dougkwan@google.com>.

// This file is part of gold.

// 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 "gold.h"
#include "elfcpp.h"
#include "dynobj.h"
#include "symtab.h"
#include "output.h"
#include "target.h"

namespace gold
{

// Return whether NAME is a local label name.  This is used to implement the
// --discard-locals options and can be overridden by child classes to
// implement system-specific behaviour.  The logic here is the same as that
// in _bfd_elf_is_local_label_name().

bool
Target::do_is_local_label_name(const char* name) const
{
  // Normal local symbols start with ``.L''.
  if (name[0] == '.' && name[1] == 'L')
    return true;

  // At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate
  // DWARF debugging symbols starting with ``..''.
  if (name[0] == '.' && name[1] == '.')
    return true;

  // gcc will sometimes generate symbols beginning with ``_.L_'' when
  // emitting DWARF debugging output.  I suspect this is actually a
  // small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call
  // ASM_GENERATE_INTERNAL_LABEL, and this causes the leading
  // underscore to be emitted on some ELF targets).  For ease of use,
  // we treat such symbols as local.
  if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
    return true;

  return false;
}

// Implementations of methods Target::do_make_elf_object are almost identical
// except for the address sizes and endianities.  So we extract this
// into a template.

template<int size, bool big_endian>
inline Object*
Target::do_make_elf_object_implementation(
    const std::string& name,
    Input_file* input_file,
    off_t offset,
    const elfcpp::Ehdr<size, big_endian>& ehdr)
{
  int et = ehdr.get_e_type();
  // ET_EXEC files are valid input for --just-symbols/-R,
  // and we treat them as relocatable objects.
  if (et == elfcpp::ET_REL
      || (et == elfcpp::ET_EXEC && input_file->just_symbols()))
    {
      Sized_relobj_file<size, big_endian>* obj =
	new Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr);
      obj->setup();
      return obj;
    }
  else if (et == elfcpp::ET_DYN)
    {
      Sized_dynobj<size, big_endian>* obj =
	new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
      obj->setup();
      return obj;
    }
  else
    {
      gold_error(_("%s: unsupported ELF file type %d"),
		 name.c_str(), et);
      return NULL;
    }
}

// Make an ELF object called NAME by reading INPUT_FILE at OFFSET.  EHDR
// is the ELF header of the object.  There are four versions of this
// for different address sizes and endianities.

#ifdef HAVE_TARGET_32_LITTLE
Object*
Target::do_make_elf_object(const std::string& name, Input_file* input_file,
			   off_t offset, const elfcpp::Ehdr<32, false>& ehdr)
{
  return this->do_make_elf_object_implementation<32, false>(name, input_file,
							    offset, ehdr);
}
#endif

#ifdef HAVE_TARGET_32_BIG
Object*
Target::do_make_elf_object(const std::string& name, Input_file* input_file,
			   off_t offset, const elfcpp::Ehdr<32, true>& ehdr)
{
  return this->do_make_elf_object_implementation<32, true>(name, input_file,
							   offset, ehdr);
}
#endif

#ifdef HAVE_TARGET_64_LITTLE
Object*
Target::do_make_elf_object(const std::string& name, Input_file* input_file,
			   off_t offset, const elfcpp::Ehdr<64, false>& ehdr)
{
  return this->do_make_elf_object_implementation<64, false>(name, input_file,
							    offset, ehdr);
}
#endif

#ifdef HAVE_TARGET_64_BIG
Object*
Target::do_make_elf_object(const std::string& name, Input_file* input_file,
			   off_t offset, const elfcpp::Ehdr<64, true>& ehdr)
{
  return this->do_make_elf_object_implementation<64, true>(name, input_file,
							   offset, ehdr);
}
#endif

Output_section*
Target::do_make_output_section(const char* name, elfcpp::Elf_Word type,
			       elfcpp::Elf_Xword flags)
{
  return new Output_section(name, type, flags);
}

// Default for whether a reloc is a call to a non-split function is
// whether the symbol is a function.

bool
Target::do_is_call_to_non_split(const Symbol* sym, const unsigned char*,
				const unsigned char*, section_size_type) const
{
  return sym->type() == elfcpp::STT_FUNC;
}

// Default conversion for -fsplit-stack is to give an error.

void
Target::do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
			   section_size_type, const unsigned char*, size_t,
			   unsigned char*, section_size_type,
			   std::string*, std::string*) const
{
  static bool warned;
  if (!warned)
    {
      gold_error(_("linker does not include stack split support "
		   "required by %s"),
		 object->name().c_str());
      warned = true;
    }
}

//  Return whether BYTES/LEN matches VIEW/VIEW_SIZE at OFFSET.

bool
Target::match_view(const unsigned char* view, section_size_type view_size,
		   section_offset_type offset, const char* bytes,
		   size_t len) const
{
  if (offset + len > view_size)
    return false;
  return memcmp(view + offset, bytes, len) == 0;
}

// Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
// for LEN bytes.

void
Target::set_view_to_nop(unsigned char* view, section_size_type view_size,
			section_offset_type offset, size_t len) const
{
  gold_assert(offset >= 0 && offset + len <= view_size);
  if (!this->has_code_fill())
    memset(view + offset, 0, len);
  else
    {
      std::string fill = this->code_fill(len);
      memcpy(view + offset, fill.data(), len);
    }
}

// Return address and size to plug into eh_frame FDEs associated with a PLT.
void
Target::do_plt_fde_location(const Output_data* plt, unsigned char*,
			    uint64_t* address, off_t* len) const
{
  *address = plt->address();
  *len = plt->data_size();
}

// Class Sized_target.

// Set the EI_OSABI field of the ELF header if requested.

template<int size, bool big_endian>
void
Sized_target<size, big_endian>::do_adjust_elf_header(unsigned char* view,
						     int len)
{
  elfcpp::ELFOSABI osabi = this->osabi();
  if (osabi != elfcpp::ELFOSABI_NONE)
    {
      gold_assert(len == elfcpp::Elf_sizes<size>::ehdr_size);

      elfcpp::Ehdr<size, big_endian> ehdr(view);
      unsigned char e_ident[elfcpp::EI_NIDENT];
      memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT);

      e_ident[elfcpp::EI_OSABI] = osabi;

      elfcpp::Ehdr_write<size, big_endian> oehdr(view);
      oehdr.put_e_ident(e_ident);
    }
}

#ifdef HAVE_TARGET_32_LITTLE
template
class Sized_target<32, false>;
#endif

#ifdef HAVE_TARGET_32_BIG
template
class Sized_target<32, true>;
#endif

#ifdef HAVE_TARGET_64_LITTLE
template
class Sized_target<64, false>;
#endif

#ifdef HAVE_TARGET_64_BIG
template
class Sized_target<64, true>;
#endif

} // End namespace gold.