]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gold/reloc.cc
Snapshot. Now able to produce a minimal executable which actually
[thirdparty/binutils-gdb.git] / gold / reloc.cc
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.