]>
Commit | Line | Data |
---|---|---|
61ba1cf9 ILT |
1 | // reloc.cc -- relocate input files for gold. |
2 | ||
3 | #include "gold.h" | |
4 | ||
5 | #include "workqueue.h" | |
6 | #include "object.h" | |
7 | #include "output.h" | |
8 | #include "reloc.h" | |
9 | ||
10 | namespace gold | |
11 | { | |
12 | ||
13 | // Relocate_task methods. | |
14 | ||
15 | // These tasks are always runnable. | |
16 | ||
17 | Task::Is_runnable_type | |
18 | Relocate_task::is_runnable(Workqueue*) | |
19 | { | |
20 | return IS_RUNNABLE; | |
21 | } | |
22 | ||
23 | // We want to lock the file while we run. We want to unblock | |
24 | // FINAL_BLOCKER when we are done. | |
25 | ||
26 | class Relocate_task::Relocate_locker : public Task_locker | |
27 | { | |
28 | public: | |
29 | Relocate_locker(Task_token& token, Workqueue* workqueue, | |
30 | Object* object) | |
31 | : blocker_(token, workqueue), objlock_(*object) | |
32 | { } | |
33 | ||
34 | private: | |
35 | Task_locker_block blocker_; | |
36 | Task_locker_obj<Object> objlock_; | |
37 | }; | |
38 | ||
39 | Task_locker* | |
40 | Relocate_task::locks(Workqueue* workqueue) | |
41 | { | |
42 | return new Relocate_locker(*this->final_blocker_, workqueue, | |
43 | this->object_); | |
44 | } | |
45 | ||
46 | // Run the task. | |
47 | ||
48 | void | |
49 | Relocate_task::run(Workqueue*) | |
50 | { | |
51 | this->object_->relocate(this->options_, this->symtab_, this->sympool_, | |
52 | this->of_); | |
53 | } | |
54 | ||
55 | // Relocate the input sections and write out the local symbols. | |
56 | ||
57 | template<int size, bool big_endian> | |
58 | void | |
59 | Sized_object<size, big_endian>::do_relocate(const General_options&, | |
60 | const Symbol_table* symtab, | |
61 | const Stringpool* sympool, | |
62 | Output_file* of) | |
63 | { | |
64 | unsigned int shnum = this->shnum(); | |
65 | ||
66 | // Read the section headers. | |
67 | const unsigned char* pshdrs = this->get_view(this->shoff_, | |
68 | shnum * This::shdr_size); | |
69 | ||
70 | Views views; | |
71 | views.resize(shnum); | |
72 | ||
73 | // Make two passes over the sections. The first one copies the | |
74 | // section data to the output file. The second one applies | |
75 | // relocations. | |
76 | ||
77 | this->write_sections(pshdrs, of, &views); | |
78 | ||
79 | // Apply relocations. | |
80 | ||
81 | this->relocate_sections(symtab, pshdrs, &views); | |
82 | ||
83 | // Write out the accumulated views. | |
84 | for (unsigned int i = 1; i < shnum; ++i) | |
85 | { | |
86 | if (views[i].view != NULL) | |
87 | of->write_output_view(views[i].offset, views[i].view_size, | |
88 | views[i].view); | |
89 | } | |
90 | ||
91 | // Write out the local symbols. | |
92 | this->write_local_symbols(of, sympool); | |
93 | } | |
94 | ||
95 | // Write section data to the output file. PSHDRS points to the | |
96 | // section headers. Record the views in *PVIEWS for use when | |
97 | // relocating. | |
98 | ||
99 | template<int size, bool big_endian> | |
100 | void | |
101 | Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs, | |
102 | Output_file* of, | |
103 | Views* pviews) | |
104 | { | |
105 | unsigned int shnum = this->shnum(); | |
106 | std::vector<Map_to_output>& map_sections(this->map_to_output()); | |
107 | ||
108 | const unsigned char* p = pshdrs + This::shdr_size; | |
109 | for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size) | |
110 | { | |
111 | View_size* pvs = &(*pviews)[i]; | |
112 | ||
113 | pvs->view = NULL; | |
114 | ||
115 | const Output_section* os = map_sections[i].output_section; | |
116 | if (os == NULL) | |
117 | continue; | |
118 | ||
119 | typename This::Shdr shdr(p); | |
120 | ||
121 | if (shdr.get_sh_type() == elfcpp::SHT_NOBITS) | |
122 | continue; | |
123 | ||
124 | assert(map_sections[i].offset >= 0 | |
125 | && map_sections[i].offset < os->data_size()); | |
126 | off_t start = os->offset() + map_sections[i].offset; | |
127 | off_t sh_size = shdr.get_sh_size(); | |
128 | ||
129 | unsigned char* view = of->get_output_view(start, sh_size); | |
130 | this->input_file()->file().read(shdr.get_sh_offset(), | |
131 | sh_size, | |
132 | view); | |
133 | pvs->view = view; | |
134 | pvs->address = os->address() + map_sections[i].offset; | |
135 | pvs->offset = start; | |
136 | pvs->view_size = sh_size; | |
137 | } | |
138 | } | |
139 | ||
140 | // Relocate section data. VIEWS points to the section data as views | |
141 | // in the output file. | |
142 | ||
143 | template<int size, bool big_endian> | |
144 | void | |
145 | Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab, | |
146 | const unsigned char* pshdrs, | |
147 | Views* pviews) | |
148 | { | |
149 | unsigned int shnum = this->shnum(); | |
150 | std::vector<Map_to_output>& map_sections(this->map_to_output()); | |
151 | Sized_target<size, big_endian>* target = this->sized_target(); | |
152 | ||
153 | const unsigned char* p = pshdrs + This::shdr_size; | |
154 | for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size) | |
155 | { | |
156 | typename This::Shdr shdr(p); | |
157 | ||
158 | unsigned int sh_type = shdr.get_sh_type(); | |
159 | if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA) | |
160 | continue; | |
161 | ||
162 | unsigned int index = shdr.get_sh_info(); | |
163 | if (index >= this->shnum()) | |
164 | { | |
165 | fprintf(stderr, _("%s: %s: relocation section %u has bad info %u\n"), | |
166 | program_name, this->name().c_str(), i, index); | |
167 | gold_exit(false); | |
168 | } | |
169 | ||
170 | if (map_sections[index].output_section == NULL) | |
171 | { | |
172 | // This relocation section is against a section which we | |
173 | // discarded. | |
174 | continue; | |
175 | } | |
176 | ||
177 | assert((*pviews)[index].view != NULL); | |
178 | ||
179 | if (shdr.get_sh_link() != this->symtab_shnum_) | |
180 | { | |
181 | fprintf(stderr, | |
182 | _("%s: %s: relocation section %u uses unexpected " | |
183 | "symbol table %u\n"), | |
184 | program_name, this->name().c_str(), i, shdr.get_sh_link()); | |
185 | gold_exit(false); | |
186 | } | |
187 | ||
188 | off_t sh_size = shdr.get_sh_size(); | |
189 | const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(), | |
190 | sh_size); | |
191 | ||
192 | unsigned int reloc_size; | |
193 | if (sh_type == elfcpp::SHT_REL) | |
194 | reloc_size = elfcpp::Elf_sizes<size>::rel_size; | |
195 | else | |
196 | reloc_size = elfcpp::Elf_sizes<size>::rela_size; | |
197 | ||
198 | if (reloc_size != shdr.get_sh_entsize()) | |
199 | { | |
200 | fprintf(stderr, | |
201 | _("%s: %s: unexpected entsize for reloc section %u: " | |
202 | "%lu != %u"), | |
203 | program_name, this->name().c_str(), i, | |
204 | static_cast<unsigned long>(shdr.get_sh_entsize()), | |
205 | reloc_size); | |
206 | gold_exit(false); | |
207 | } | |
208 | ||
209 | size_t reloc_count = sh_size / reloc_size; | |
210 | if (reloc_count * reloc_size != sh_size) | |
211 | { | |
212 | fprintf(stderr, _("%s: %s: reloc section %u size %lu uneven"), | |
213 | program_name, this->name().c_str(), i, | |
214 | static_cast<unsigned long>(sh_size)); | |
215 | gold_exit(false); | |
216 | } | |
217 | ||
218 | target->relocate_section(symtab, this, sh_type, prelocs, reloc_count, | |
219 | this->local_symbol_count_, | |
220 | this->values_, | |
221 | this->symbols_, | |
222 | (*pviews)[index].view, | |
223 | (*pviews)[index].address, | |
224 | (*pviews)[index].view_size); | |
225 | } | |
226 | } | |
227 | ||
228 | // Instantiate the templates we need. We could use the configure | |
229 | // script to restrict this to only the ones for implemented targets. | |
230 | ||
231 | template | |
232 | void | |
233 | Sized_object<32, false>::do_relocate(const General_options& options, | |
234 | const Symbol_table* symtab, | |
235 | const Stringpool* sympool, | |
236 | Output_file* of); | |
237 | ||
238 | template | |
239 | void | |
240 | Sized_object<32, true>::do_relocate(const General_options& options, | |
241 | const Symbol_table* symtab, | |
242 | const Stringpool* sympool, | |
243 | Output_file* of); | |
244 | ||
245 | template | |
246 | void | |
247 | Sized_object<64, false>::do_relocate(const General_options& options, | |
248 | const Symbol_table* symtab, | |
249 | const Stringpool* sympool, | |
250 | Output_file* of); | |
251 | ||
252 | template | |
253 | void | |
254 | Sized_object<64, true>::do_relocate(const General_options& options, | |
255 | const Symbol_table* symtab, | |
256 | const Stringpool* sympool, | |
257 | Output_file* of); | |
258 | ||
259 | ||
260 | } // End namespace gold. |