Snapshot. Now able to produce a minimal executable which actually
[external/binutils.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.