Commit | Line | Data |
---|---|---|
12c0daef ILT |
1 | // copy-relocs.cc -- handle COPY relocations for gold. |
2 | ||
2571583a | 3 | // Copyright (C) 2006-2017 Free Software Foundation, Inc. |
12c0daef ILT |
4 | // Written by Ian Lance Taylor <iant@google.com>. |
5 | ||
6 | // This file is part of gold. | |
7 | ||
8 | // This program is free software; you can redistribute it and/or modify | |
9 | // it under the terms of the GNU General Public License as published by | |
10 | // the Free Software Foundation; either version 3 of the License, or | |
11 | // (at your option) any later version. | |
12 | ||
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | ||
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | |
21 | // MA 02110-1301, USA. | |
22 | ||
23 | #include "gold.h" | |
24 | ||
25 | #include "symtab.h" | |
26 | #include "copy-relocs.h" | |
27 | ||
28 | namespace gold | |
29 | { | |
30 | ||
12c0daef ILT |
31 | // Copy_relocs methods. |
32 | ||
33 | // Handle a relocation against a symbol which may force us to generate | |
34 | // a COPY reloc. | |
35 | ||
36 | template<int sh_type, int size, bool big_endian> | |
37 | void | |
38 | Copy_relocs<sh_type, size, big_endian>::copy_reloc( | |
39 | Symbol_table* symtab, | |
40 | Layout* layout, | |
41 | Sized_symbol<size>* sym, | |
6fa2a40b | 42 | Sized_relobj_file<size, big_endian>* object, |
12c0daef | 43 | unsigned int shndx, |
ca09d69a | 44 | Output_section* output_section, |
859d7987 CC |
45 | unsigned int r_type, |
46 | typename elfcpp::Elf_types<size>::Elf_Addr r_offset, | |
47 | typename elfcpp::Elf_types<size>::Elf_Swxword r_addend, | |
12c0daef ILT |
48 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) |
49 | { | |
50 | if (this->need_copy_reloc(sym, object, shndx)) | |
6eeb0170 | 51 | this->make_copy_reloc(symtab, layout, sym, object, reloc_section); |
12c0daef ILT |
52 | else |
53 | { | |
54 | // We may not need a COPY relocation. Save this relocation to | |
55 | // possibly be emitted later. | |
859d7987 CC |
56 | this->save(sym, object, shndx, output_section, |
57 | r_type, r_offset, r_addend); | |
12c0daef ILT |
58 | } |
59 | } | |
60 | ||
61 | // Return whether we need a COPY reloc for a relocation against SYM. | |
62 | // The relocation is begin applied to section SHNDX in OBJECT. | |
63 | ||
64 | template<int sh_type, int size, bool big_endian> | |
65 | bool | |
66 | Copy_relocs<sh_type, size, big_endian>::need_copy_reloc( | |
67 | Sized_symbol<size>* sym, | |
6fa2a40b | 68 | Sized_relobj_file<size, big_endian>* object, |
12c0daef ILT |
69 | unsigned int shndx) const |
70 | { | |
966d4097 DK |
71 | if (!parameters->options().copyreloc()) |
72 | return false; | |
12c0daef ILT |
73 | |
74 | if (sym->symsize() == 0) | |
75 | return false; | |
76 | ||
77 | // If this is a readonly section, then we need a COPY reloc. | |
78 | // Otherwise we can use a dynamic reloc. Note that calling | |
79 | // section_flags here can be slow, as the information is not cached; | |
80 | // fortunately we shouldn't see too many potential COPY relocs. | |
81 | if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0) | |
82 | return true; | |
83 | ||
84 | return false; | |
85 | } | |
86 | ||
87 | // Emit a COPY relocation for SYM. | |
88 | ||
89 | template<int sh_type, int size, bool big_endian> | |
90 | void | |
91 | Copy_relocs<sh_type, size, big_endian>::emit_copy_reloc( | |
26d3c67d CC |
92 | Symbol_table* symtab, |
93 | Sized_symbol<size>* sym, | |
94 | Output_data* posd, | |
95 | off_t offset, | |
96 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) | |
97 | { | |
98 | // Define the symbol as being copied. | |
99 | symtab->define_with_copy_reloc(sym, posd, offset); | |
100 | ||
101 | // Add the COPY relocation to the dynamic reloc section. | |
83896202 ILT |
102 | reloc_section->add_global_generic(sym, this->copy_reloc_type_, posd, |
103 | offset, 0); | |
26d3c67d CC |
104 | } |
105 | ||
106 | // Make a COPY relocation for SYM and emit it. | |
107 | ||
108 | template<int sh_type, int size, bool big_endian> | |
109 | void | |
110 | Copy_relocs<sh_type, size, big_endian>::make_copy_reloc( | |
12c0daef ILT |
111 | Symbol_table* symtab, |
112 | Layout* layout, | |
113 | Sized_symbol<size>* sym, | |
6eeb0170 | 114 | Sized_relobj_file<size, big_endian>* object, |
12c0daef ILT |
115 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) |
116 | { | |
966d4097 DK |
117 | // We should not be here if -z nocopyreloc is given. |
118 | gold_assert(parameters->options().copyreloc()); | |
119 | ||
6eeb0170 CC |
120 | gold_assert(sym->is_from_dynobj()); |
121 | ||
122 | // The symbol must not have protected visibility. | |
123 | if (sym->is_protected()) | |
124 | { | |
125 | gold_error(_("%s: cannot make copy relocation for " | |
126 | "protected symbol '%s', defined in %s"), | |
127 | object->name().c_str(), | |
128 | sym->name(), | |
129 | sym->object()->name().c_str()); | |
130 | } | |
131 | ||
12c0daef ILT |
132 | typename elfcpp::Elf_types<size>::Elf_WXword symsize = sym->symsize(); |
133 | ||
134 | // There is no defined way to determine the required alignment of | |
135 | // the symbol. We know that the symbol is defined in a dynamic | |
136 | // object. We start with the alignment of the section in which it | |
137 | // is defined; presumably we do not require an alignment larger than | |
138 | // that. Then we reduce that alignment if the symbol is not aligned | |
139 | // within the section. | |
d491d34e ILT |
140 | bool is_ordinary; |
141 | unsigned int shndx = sym->shndx(&is_ordinary); | |
142 | gold_assert(is_ordinary); | |
5f9bcf58 | 143 | typename elfcpp::Elf_types<size>::Elf_WXword addralign; |
b733bcb7 | 144 | bool is_readonly = false; |
5f9bcf58 CC |
145 | |
146 | { | |
147 | // Lock the object so we can read from it. This is only called | |
148 | // single-threaded from scan_relocs, so it is OK to lock. | |
149 | // Unfortunately we have no way to pass in a Task token. | |
150 | const Task* dummy_task = reinterpret_cast<const Task*>(-1); | |
151 | Object* obj = sym->object(); | |
152 | Task_lock_obj<Object> tl(dummy_task, obj); | |
153 | addralign = obj->section_addralign(shndx); | |
b733bcb7 CC |
154 | if (parameters->options().relro()) |
155 | { | |
156 | if ((obj->section_flags(shndx) & elfcpp::SHF_WRITE) == 0) | |
157 | is_readonly = true; | |
158 | else | |
159 | { | |
160 | // Symbols in .data.rel.ro should also be treated as read-only. | |
161 | if (obj->section_name(shndx) == ".data.rel.ro") | |
162 | is_readonly = true; | |
163 | } | |
164 | } | |
5f9bcf58 | 165 | } |
12c0daef ILT |
166 | |
167 | typename Sized_symbol<size>::Value_type value = sym->value(); | |
168 | while ((value & (addralign - 1)) != 0) | |
169 | addralign >>= 1; | |
170 | ||
659948a4 ILT |
171 | // Mark the dynamic object as needed for the --as-needed option. |
172 | sym->object()->set_is_needed(); | |
173 | ||
b733bcb7 CC |
174 | Output_data_space* dynbss; |
175 | ||
176 | if (is_readonly) | |
12c0daef | 177 | { |
b733bcb7 CC |
178 | if (this->dynrelro_ == NULL) |
179 | { | |
180 | this->dynrelro_ = new Output_data_space(addralign, "** dynrelro"); | |
181 | layout->add_output_section_data(".data.rel.ro", | |
182 | elfcpp::SHT_PROGBITS, | |
183 | elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, | |
184 | this->dynrelro_, ORDER_RELRO, false); | |
185 | } | |
186 | dynbss = this->dynrelro_; | |
187 | } | |
188 | else | |
189 | { | |
190 | if (this->dynbss_ == NULL) | |
191 | { | |
192 | this->dynbss_ = new Output_data_space(addralign, "** dynbss"); | |
193 | layout->add_output_section_data(".bss", | |
194 | elfcpp::SHT_NOBITS, | |
195 | elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, | |
196 | this->dynbss_, ORDER_BSS, false); | |
197 | } | |
198 | dynbss = this->dynbss_; | |
12c0daef | 199 | } |
12c0daef ILT |
200 | |
201 | if (addralign > dynbss->addralign()) | |
202 | dynbss->set_space_alignment(addralign); | |
203 | ||
204 | section_size_type dynbss_size = | |
205 | convert_to_section_size_type(dynbss->current_data_size()); | |
206 | dynbss_size = align_address(dynbss_size, addralign); | |
207 | section_size_type offset = dynbss_size; | |
208 | dynbss->set_current_data_size(dynbss_size + symsize); | |
209 | ||
26d3c67d | 210 | this->emit_copy_reloc(symtab, sym, dynbss, offset, reloc_section); |
12c0daef ILT |
211 | } |
212 | ||
213 | // Save a relocation to possibly be emitted later. | |
214 | ||
215 | template<int sh_type, int size, bool big_endian> | |
216 | void | |
ef9beddf ILT |
217 | Copy_relocs<sh_type, size, big_endian>::save( |
218 | Symbol* sym, | |
6fa2a40b | 219 | Sized_relobj_file<size, big_endian>* object, |
ef9beddf ILT |
220 | unsigned int shndx, |
221 | Output_section* output_section, | |
859d7987 CC |
222 | unsigned int r_type, |
223 | typename elfcpp::Elf_types<size>::Elf_Addr r_offset, | |
224 | typename elfcpp::Elf_types<size>::Elf_Swxword r_addend) | |
12c0daef | 225 | { |
859d7987 CC |
226 | this->entries_.push_back(Copy_reloc_entry(sym, r_type, object, shndx, |
227 | output_section, r_offset, | |
228 | r_addend)); | |
12c0daef ILT |
229 | } |
230 | ||
231 | // Emit any saved relocs. | |
232 | ||
233 | template<int sh_type, int size, bool big_endian> | |
234 | void | |
235 | Copy_relocs<sh_type, size, big_endian>::emit( | |
236 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) | |
237 | { | |
238 | for (typename Copy_reloc_entries::iterator p = this->entries_.begin(); | |
239 | p != this->entries_.end(); | |
240 | ++p) | |
91f43acd CC |
241 | { |
242 | Copy_reloc_entry& entry = *p; | |
243 | ||
244 | // If the symbol is no longer defined in a dynamic object, then we | |
245 | // emitted a COPY relocation, and we do not want to emit this | |
246 | // dynamic relocation. | |
247 | if (entry.sym_->is_from_dynobj()) | |
248 | reloc_section->add_global_generic(entry.sym_, entry.reloc_type_, | |
249 | entry.output_section_, entry.relobj_, | |
250 | entry.shndx_, entry.address_, | |
251 | entry.addend_); | |
252 | } | |
12c0daef ILT |
253 | |
254 | // We no longer need the saved information. | |
255 | this->entries_.clear(); | |
256 | } | |
257 | ||
258 | // Instantiate the templates we need. | |
259 | ||
260 | #ifdef HAVE_TARGET_32_LITTLE | |
261 | template | |
262 | class Copy_relocs<elfcpp::SHT_REL, 32, false>; | |
263 | ||
264 | template | |
265 | class Copy_relocs<elfcpp::SHT_RELA, 32, false>; | |
266 | #endif | |
267 | ||
268 | #ifdef HAVE_TARGET_32_BIG | |
269 | template | |
270 | class Copy_relocs<elfcpp::SHT_REL, 32, true>; | |
271 | ||
272 | template | |
273 | class Copy_relocs<elfcpp::SHT_RELA, 32, true>; | |
274 | #endif | |
275 | ||
276 | #ifdef HAVE_TARGET_64_LITTLE | |
277 | template | |
278 | class Copy_relocs<elfcpp::SHT_REL, 64, false>; | |
279 | ||
280 | template | |
281 | class Copy_relocs<elfcpp::SHT_RELA, 64, false>; | |
282 | #endif | |
283 | ||
284 | #ifdef HAVE_TARGET_64_BIG | |
285 | template | |
286 | class Copy_relocs<elfcpp::SHT_REL, 64, true>; | |
287 | ||
288 | template | |
289 | class Copy_relocs<elfcpp::SHT_RELA, 64, true>; | |
290 | #endif | |
291 | ||
292 | } // End namespace gold. |