Commit | Line | Data |
---|---|---|
12c0daef ILT |
1 | // copy-relocs.cc -- handle COPY relocations for gold. |
2 | ||
3 | // Copyright 2006, 2007, 2008 Free Software Foundation, Inc. | |
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 | ||
31 | // Copy_relocs::Copy_reloc_entry methods. | |
32 | ||
33 | // Emit the reloc if appropriate. | |
34 | ||
35 | template<int sh_type, int size, bool big_endian> | |
36 | void | |
37 | Copy_relocs<sh_type, size, big_endian>::Copy_reloc_entry::emit( | |
38 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) | |
39 | { | |
40 | // If the symbol is no longer defined in a dynamic object, then we | |
41 | // emitted a COPY relocation, and we do not want to emit this | |
42 | // dynamic relocation. | |
43 | if (this->sym_->is_from_dynobj()) | |
44 | reloc_section->add_global(this->sym_, this->reloc_type_, | |
45 | this->output_section_, this->relobj_, | |
46 | this->shndx_, this->address_, | |
47 | this->addend_); | |
48 | } | |
49 | ||
50 | // Copy_relocs methods. | |
51 | ||
52 | // Handle a relocation against a symbol which may force us to generate | |
53 | // a COPY reloc. | |
54 | ||
55 | template<int sh_type, int size, bool big_endian> | |
56 | void | |
57 | Copy_relocs<sh_type, size, big_endian>::copy_reloc( | |
58 | Symbol_table* symtab, | |
59 | Layout* layout, | |
60 | Sized_symbol<size>* sym, | |
ef9beddf | 61 | Sized_relobj<size, big_endian>* object, |
12c0daef ILT |
62 | unsigned int shndx, |
63 | Output_section *output_section, | |
64 | const Reloc& rel, | |
65 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) | |
66 | { | |
67 | if (this->need_copy_reloc(sym, object, shndx)) | |
68 | this->emit_copy_reloc(symtab, layout, sym, reloc_section); | |
69 | else | |
70 | { | |
71 | // We may not need a COPY relocation. Save this relocation to | |
72 | // possibly be emitted later. | |
73 | this->save(sym, object, shndx, output_section, rel); | |
74 | } | |
75 | } | |
76 | ||
77 | // Return whether we need a COPY reloc for a relocation against SYM. | |
78 | // The relocation is begin applied to section SHNDX in OBJECT. | |
79 | ||
80 | template<int sh_type, int size, bool big_endian> | |
81 | bool | |
82 | Copy_relocs<sh_type, size, big_endian>::need_copy_reloc( | |
83 | Sized_symbol<size>* sym, | |
ef9beddf | 84 | Sized_relobj<size, big_endian>* object, |
12c0daef ILT |
85 | unsigned int shndx) const |
86 | { | |
87 | // FIXME: Handle -z nocopyrelocs. | |
88 | ||
89 | if (sym->symsize() == 0) | |
90 | return false; | |
91 | ||
92 | // If this is a readonly section, then we need a COPY reloc. | |
93 | // Otherwise we can use a dynamic reloc. Note that calling | |
94 | // section_flags here can be slow, as the information is not cached; | |
95 | // fortunately we shouldn't see too many potential COPY relocs. | |
96 | if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0) | |
97 | return true; | |
98 | ||
99 | return false; | |
100 | } | |
101 | ||
102 | // Emit a COPY relocation for SYM. | |
103 | ||
104 | template<int sh_type, int size, bool big_endian> | |
105 | void | |
106 | Copy_relocs<sh_type, size, big_endian>::emit_copy_reloc( | |
107 | Symbol_table* symtab, | |
108 | Layout* layout, | |
109 | Sized_symbol<size>* sym, | |
110 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) | |
111 | { | |
112 | typename elfcpp::Elf_types<size>::Elf_WXword symsize = sym->symsize(); | |
113 | ||
114 | // There is no defined way to determine the required alignment of | |
115 | // the symbol. We know that the symbol is defined in a dynamic | |
116 | // object. We start with the alignment of the section in which it | |
117 | // is defined; presumably we do not require an alignment larger than | |
118 | // that. Then we reduce that alignment if the symbol is not aligned | |
119 | // within the section. | |
120 | gold_assert(sym->is_from_dynobj()); | |
d491d34e ILT |
121 | bool is_ordinary; |
122 | unsigned int shndx = sym->shndx(&is_ordinary); | |
123 | gold_assert(is_ordinary); | |
12c0daef | 124 | typename elfcpp::Elf_types<size>::Elf_WXword addralign = |
d491d34e | 125 | sym->object()->section_addralign(shndx); |
12c0daef ILT |
126 | |
127 | typename Sized_symbol<size>::Value_type value = sym->value(); | |
128 | while ((value & (addralign - 1)) != 0) | |
129 | addralign >>= 1; | |
130 | ||
131 | if (this->dynbss_ == NULL) | |
132 | { | |
7d9e3d98 | 133 | this->dynbss_ = new Output_data_space(addralign, "** dynbss"); |
12c0daef ILT |
134 | layout->add_output_section_data(".bss", |
135 | elfcpp::SHT_NOBITS, | |
136 | elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, | |
137 | this->dynbss_); | |
138 | } | |
139 | ||
140 | Output_data_space* dynbss = this->dynbss_; | |
141 | ||
142 | if (addralign > dynbss->addralign()) | |
143 | dynbss->set_space_alignment(addralign); | |
144 | ||
145 | section_size_type dynbss_size = | |
146 | convert_to_section_size_type(dynbss->current_data_size()); | |
147 | dynbss_size = align_address(dynbss_size, addralign); | |
148 | section_size_type offset = dynbss_size; | |
149 | dynbss->set_current_data_size(dynbss_size + symsize); | |
150 | ||
151 | // Define the symbol as being copied. | |
152 | symtab->define_with_copy_reloc(sym, dynbss, offset); | |
153 | ||
154 | // Add the COPY relocation to the dynamic reloc section. | |
155 | this->add_copy_reloc(sym, offset, reloc_section); | |
156 | } | |
157 | ||
158 | // Add a COPY relocation for SYM to RELOC_SECTION. | |
159 | ||
160 | template<int sh_type, int size, bool big_endian> | |
161 | void | |
162 | Copy_relocs<sh_type, size, big_endian>::add_copy_reloc( | |
163 | Symbol* sym, | |
164 | section_size_type offset, | |
165 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) | |
166 | { | |
167 | reloc_section->add_global(sym, this->copy_reloc_type_, this->dynbss_, | |
168 | offset, 0); | |
169 | } | |
170 | ||
171 | // Save a relocation to possibly be emitted later. | |
172 | ||
173 | template<int sh_type, int size, bool big_endian> | |
174 | void | |
ef9beddf ILT |
175 | Copy_relocs<sh_type, size, big_endian>::save( |
176 | Symbol* sym, | |
177 | Sized_relobj<size, big_endian>* object, | |
178 | unsigned int shndx, | |
179 | Output_section* output_section, | |
180 | const Reloc& rel) | |
12c0daef ILT |
181 | { |
182 | unsigned int reloc_type = elfcpp::elf_r_type<size>(rel.get_r_info()); | |
183 | typename elfcpp::Elf_types<size>::Elf_Addr addend = | |
184 | Reloc_types<sh_type, size, big_endian>::get_reloc_addend_noerror(&rel); | |
185 | this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, object, shndx, | |
186 | output_section, rel.get_r_offset(), | |
187 | addend)); | |
188 | } | |
189 | ||
190 | // Emit any saved relocs. | |
191 | ||
192 | template<int sh_type, int size, bool big_endian> | |
193 | void | |
194 | Copy_relocs<sh_type, size, big_endian>::emit( | |
195 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) | |
196 | { | |
197 | for (typename Copy_reloc_entries::iterator p = this->entries_.begin(); | |
198 | p != this->entries_.end(); | |
199 | ++p) | |
200 | p->emit(reloc_section); | |
201 | ||
202 | // We no longer need the saved information. | |
203 | this->entries_.clear(); | |
204 | } | |
205 | ||
206 | // Instantiate the templates we need. | |
207 | ||
208 | #ifdef HAVE_TARGET_32_LITTLE | |
209 | template | |
210 | class Copy_relocs<elfcpp::SHT_REL, 32, false>; | |
211 | ||
212 | template | |
213 | class Copy_relocs<elfcpp::SHT_RELA, 32, false>; | |
214 | #endif | |
215 | ||
216 | #ifdef HAVE_TARGET_32_BIG | |
217 | template | |
218 | class Copy_relocs<elfcpp::SHT_REL, 32, true>; | |
219 | ||
220 | template | |
221 | class Copy_relocs<elfcpp::SHT_RELA, 32, true>; | |
222 | #endif | |
223 | ||
224 | #ifdef HAVE_TARGET_64_LITTLE | |
225 | template | |
226 | class Copy_relocs<elfcpp::SHT_REL, 64, false>; | |
227 | ||
228 | template | |
229 | class Copy_relocs<elfcpp::SHT_RELA, 64, false>; | |
230 | #endif | |
231 | ||
232 | #ifdef HAVE_TARGET_64_BIG | |
233 | template | |
234 | class Copy_relocs<elfcpp::SHT_REL, 64, true>; | |
235 | ||
236 | template | |
237 | class Copy_relocs<elfcpp::SHT_RELA, 64, true>; | |
238 | #endif | |
239 | ||
240 | } // End namespace gold. |