]>
Commit | Line | Data |
---|---|---|
a2fb1b05 ILT |
1 | // output.cc -- manage the output file for gold |
2 | ||
3 | #include "gold.h" | |
4 | ||
5 | #include <cstdlib> | |
61ba1cf9 ILT |
6 | #include <cerrno> |
7 | #include <fcntl.h> | |
8 | #include <unistd.h> | |
9 | #include <sys/mman.h> | |
75f65a3e | 10 | #include <algorithm> |
a2fb1b05 ILT |
11 | |
12 | #include "object.h" | |
13 | #include "output.h" | |
14 | ||
15 | namespace gold | |
16 | { | |
17 | ||
18 | // Output_data methods. | |
19 | ||
20 | Output_data::~Output_data() | |
21 | { | |
22 | } | |
23 | ||
75f65a3e ILT |
24 | // Set the address and offset. |
25 | ||
26 | void | |
27 | Output_data::set_address(uint64_t addr, off_t off) | |
28 | { | |
29 | this->address_ = addr; | |
30 | this->offset_ = off; | |
31 | ||
32 | // Let the child class know. | |
33 | this->do_set_address(addr, off); | |
34 | } | |
35 | ||
36 | // Return the default alignment for a size--32 or 64. | |
37 | ||
38 | uint64_t | |
39 | Output_data::default_alignment(int size) | |
40 | { | |
41 | if (size == 32) | |
42 | return 4; | |
43 | else if (size == 64) | |
44 | return 8; | |
45 | else | |
46 | abort(); | |
47 | } | |
48 | ||
a2fb1b05 ILT |
49 | // Output_data_const methods. |
50 | ||
51 | void | |
75f65a3e ILT |
52 | Output_data_const::do_write(Output_file* output) |
53 | { | |
54 | output->write(this->offset(), data_.data(), data_.size()); | |
55 | } | |
56 | ||
57 | // Output_section_header methods. This currently assumes that the | |
58 | // segment and section lists are complete at construction time. | |
59 | ||
60 | Output_section_headers::Output_section_headers( | |
61 | int size, | |
61ba1cf9 | 62 | bool big_endian, |
75f65a3e | 63 | const Layout::Segment_list& segment_list, |
61ba1cf9 ILT |
64 | const Layout::Section_list& section_list, |
65 | const Stringpool* secnamepool) | |
75f65a3e | 66 | : size_(size), |
61ba1cf9 | 67 | big_endian_(big_endian), |
75f65a3e | 68 | segment_list_(segment_list), |
61ba1cf9 ILT |
69 | section_list_(section_list), |
70 | secnamepool_(secnamepool) | |
75f65a3e | 71 | { |
61ba1cf9 ILT |
72 | // Count all the sections. Start with 1 for the null section. |
73 | off_t count = 1; | |
75f65a3e ILT |
74 | for (Layout::Segment_list::const_iterator p = segment_list.begin(); |
75 | p != segment_list.end(); | |
76 | ++p) | |
77 | count += (*p)->output_section_count(); | |
78 | count += section_list.size(); | |
79 | ||
80 | int shdr_size; | |
81 | if (size == 32) | |
82 | shdr_size = elfcpp::Elf_sizes<32>::shdr_size; | |
83 | else if (size == 64) | |
84 | shdr_size = elfcpp::Elf_sizes<64>::shdr_size; | |
85 | else | |
86 | abort(); | |
87 | ||
88 | this->set_data_size(count * shdr_size); | |
89 | } | |
90 | ||
61ba1cf9 ILT |
91 | // Write out the section headers. |
92 | ||
75f65a3e | 93 | void |
61ba1cf9 | 94 | Output_section_headers::do_write(Output_file* of) |
a2fb1b05 | 95 | { |
61ba1cf9 ILT |
96 | if (this->size_ == 32) |
97 | { | |
98 | if (this->big_endian_) | |
99 | this->do_sized_write<32, true>(of); | |
100 | else | |
101 | this->do_sized_write<32, false>(of); | |
102 | } | |
103 | else if (this->size_ == 64) | |
104 | { | |
105 | if (this->big_endian_) | |
106 | this->do_sized_write<64, true>(of); | |
107 | else | |
108 | this->do_sized_write<64, false>(of); | |
109 | } | |
110 | else | |
111 | abort(); | |
112 | } | |
113 | ||
114 | template<int size, bool big_endian> | |
115 | void | |
116 | Output_section_headers::do_sized_write(Output_file* of) | |
117 | { | |
118 | off_t all_shdrs_size = this->data_size(); | |
119 | unsigned char* view = of->get_output_view(this->offset(), all_shdrs_size); | |
120 | ||
121 | const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size; | |
122 | unsigned char* v = view; | |
123 | ||
124 | { | |
125 | typename elfcpp::Shdr_write<size, big_endian> oshdr(v); | |
126 | oshdr.put_sh_name(0); | |
127 | oshdr.put_sh_type(elfcpp::SHT_NULL); | |
128 | oshdr.put_sh_flags(0); | |
129 | oshdr.put_sh_addr(0); | |
130 | oshdr.put_sh_offset(0); | |
131 | oshdr.put_sh_size(0); | |
132 | oshdr.put_sh_link(0); | |
133 | oshdr.put_sh_info(0); | |
134 | oshdr.put_sh_addralign(0); | |
135 | oshdr.put_sh_entsize(0); | |
136 | } | |
137 | ||
138 | v += shdr_size; | |
139 | ||
140 | for (Layout::Segment_list::const_iterator p = this->segment_list_.begin(); | |
141 | p != this->segment_list_.end(); | |
142 | ++p) | |
5482377d ILT |
143 | v = (*p)->write_section_headers SELECT_SIZE_ENDIAN_NAME ( |
144 | this->secnamepool_, v SELECT_SIZE_ENDIAN(size, big_endian)); | |
61ba1cf9 ILT |
145 | for (Layout::Section_list::const_iterator p = this->section_list_.begin(); |
146 | p != this->section_list_.end(); | |
147 | ++p) | |
148 | { | |
149 | elfcpp::Shdr_write<size, big_endian> oshdr(v); | |
150 | (*p)->write_header(this->secnamepool_, &oshdr); | |
151 | v += shdr_size; | |
152 | } | |
153 | ||
154 | of->write_output_view(this->offset(), all_shdrs_size, view); | |
a2fb1b05 ILT |
155 | } |
156 | ||
54dc6425 ILT |
157 | // Output_segment_header methods. |
158 | ||
61ba1cf9 ILT |
159 | Output_segment_headers::Output_segment_headers( |
160 | int size, | |
161 | bool big_endian, | |
162 | const Layout::Segment_list& segment_list) | |
163 | : size_(size), big_endian_(big_endian), segment_list_(segment_list) | |
164 | { | |
165 | int phdr_size; | |
166 | if (size == 32) | |
167 | phdr_size = elfcpp::Elf_sizes<32>::phdr_size; | |
168 | else if (size == 64) | |
169 | phdr_size = elfcpp::Elf_sizes<64>::phdr_size; | |
170 | else | |
171 | abort(); | |
172 | ||
173 | this->set_data_size(segment_list.size() * phdr_size); | |
174 | } | |
175 | ||
54dc6425 | 176 | void |
61ba1cf9 | 177 | Output_segment_headers::do_write(Output_file* of) |
75f65a3e | 178 | { |
61ba1cf9 ILT |
179 | if (this->size_ == 32) |
180 | { | |
181 | if (this->big_endian_) | |
182 | this->do_sized_write<32, true>(of); | |
183 | else | |
184 | this->do_sized_write<32, false>(of); | |
185 | } | |
186 | else if (this->size_ == 64) | |
187 | { | |
188 | if (this->big_endian_) | |
189 | this->do_sized_write<64, true>(of); | |
190 | else | |
191 | this->do_sized_write<64, false>(of); | |
192 | } | |
193 | else | |
194 | abort(); | |
195 | } | |
196 | ||
197 | template<int size, bool big_endian> | |
198 | void | |
199 | Output_segment_headers::do_sized_write(Output_file* of) | |
200 | { | |
201 | const int phdr_size = elfcpp::Elf_sizes<size>::phdr_size; | |
202 | off_t all_phdrs_size = this->segment_list_.size() * phdr_size; | |
203 | unsigned char* view = of->get_output_view(this->offset(), | |
204 | all_phdrs_size); | |
205 | unsigned char* v = view; | |
206 | for (Layout::Segment_list::const_iterator p = this->segment_list_.begin(); | |
207 | p != this->segment_list_.end(); | |
208 | ++p) | |
209 | { | |
210 | elfcpp::Phdr_write<size, big_endian> ophdr(v); | |
211 | (*p)->write_header(&ophdr); | |
212 | v += phdr_size; | |
213 | } | |
214 | ||
215 | of->write_output_view(this->offset(), all_phdrs_size, view); | |
75f65a3e ILT |
216 | } |
217 | ||
218 | // Output_file_header methods. | |
219 | ||
220 | Output_file_header::Output_file_header(int size, | |
61ba1cf9 | 221 | bool big_endian, |
75f65a3e ILT |
222 | const General_options& options, |
223 | const Target* target, | |
224 | const Symbol_table* symtab, | |
225 | const Output_segment_headers* osh) | |
226 | : size_(size), | |
61ba1cf9 | 227 | big_endian_(big_endian), |
75f65a3e ILT |
228 | options_(options), |
229 | target_(target), | |
230 | symtab_(symtab), | |
61ba1cf9 | 231 | segment_header_(osh), |
75f65a3e ILT |
232 | section_header_(NULL), |
233 | shstrtab_(NULL) | |
234 | { | |
61ba1cf9 ILT |
235 | int ehdr_size; |
236 | if (size == 32) | |
237 | ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size; | |
238 | else if (size == 64) | |
239 | ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; | |
240 | else | |
241 | abort(); | |
242 | ||
243 | this->set_data_size(ehdr_size); | |
75f65a3e ILT |
244 | } |
245 | ||
246 | // Set the section table information for a file header. | |
247 | ||
248 | void | |
249 | Output_file_header::set_section_info(const Output_section_headers* shdrs, | |
250 | const Output_section* shstrtab) | |
251 | { | |
252 | this->section_header_ = shdrs; | |
253 | this->shstrtab_ = shstrtab; | |
254 | } | |
255 | ||
256 | // Write out the file header. | |
257 | ||
258 | void | |
61ba1cf9 | 259 | Output_file_header::do_write(Output_file* of) |
54dc6425 | 260 | { |
61ba1cf9 ILT |
261 | if (this->size_ == 32) |
262 | { | |
263 | if (this->big_endian_) | |
264 | this->do_sized_write<32, true>(of); | |
265 | else | |
266 | this->do_sized_write<32, false>(of); | |
267 | } | |
268 | else if (this->size_ == 64) | |
269 | { | |
270 | if (this->big_endian_) | |
271 | this->do_sized_write<64, true>(of); | |
272 | else | |
273 | this->do_sized_write<64, false>(of); | |
274 | } | |
275 | else | |
276 | abort(); | |
277 | } | |
278 | ||
279 | // Write out the file header with appropriate size and endianess. | |
280 | ||
281 | template<int size, bool big_endian> | |
282 | void | |
283 | Output_file_header::do_sized_write(Output_file* of) | |
284 | { | |
285 | assert(this->offset() == 0); | |
286 | ||
287 | int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size; | |
288 | unsigned char* view = of->get_output_view(0, ehdr_size); | |
289 | elfcpp::Ehdr_write<size, big_endian> oehdr(view); | |
290 | ||
291 | unsigned char e_ident[elfcpp::EI_NIDENT]; | |
292 | memset(e_ident, 0, elfcpp::EI_NIDENT); | |
293 | e_ident[elfcpp::EI_MAG0] = elfcpp::ELFMAG0; | |
294 | e_ident[elfcpp::EI_MAG1] = elfcpp::ELFMAG1; | |
295 | e_ident[elfcpp::EI_MAG2] = elfcpp::ELFMAG2; | |
296 | e_ident[elfcpp::EI_MAG3] = elfcpp::ELFMAG3; | |
297 | if (size == 32) | |
298 | e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS32; | |
299 | else if (size == 64) | |
300 | e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS64; | |
301 | else | |
302 | abort(); | |
303 | e_ident[elfcpp::EI_DATA] = (big_endian | |
304 | ? elfcpp::ELFDATA2MSB | |
305 | : elfcpp::ELFDATA2LSB); | |
306 | e_ident[elfcpp::EI_VERSION] = elfcpp::EV_CURRENT; | |
307 | // FIXME: Some targets may need to set EI_OSABI and EI_ABIVERSION. | |
308 | oehdr.put_e_ident(e_ident); | |
309 | ||
310 | elfcpp::ET e_type; | |
311 | // FIXME: ET_DYN. | |
312 | if (this->options_.is_relocatable()) | |
313 | e_type = elfcpp::ET_REL; | |
314 | else | |
315 | e_type = elfcpp::ET_EXEC; | |
316 | oehdr.put_e_type(e_type); | |
317 | ||
318 | oehdr.put_e_machine(this->target_->machine_code()); | |
319 | oehdr.put_e_version(elfcpp::EV_CURRENT); | |
320 | ||
321 | Symbol* sym = this->symtab_->lookup("_start"); | |
322 | typename Sized_symbol<size>::Value_type v; | |
323 | if (sym == NULL) | |
324 | v = 0; | |
325 | else | |
326 | { | |
327 | Sized_symbol<size>* ssym; | |
5482377d ILT |
328 | ssym = this->symtab_->get_sized_symbol SELECT_SIZE_NAME ( |
329 | sym SELECT_SIZE(size)); | |
61ba1cf9 ILT |
330 | v = ssym->value(); |
331 | } | |
332 | oehdr.put_e_entry(v); | |
333 | ||
334 | oehdr.put_e_phoff(this->segment_header_->offset()); | |
335 | oehdr.put_e_shoff(this->section_header_->offset()); | |
336 | ||
337 | // FIXME: The target needs to set the flags. | |
338 | oehdr.put_e_flags(0); | |
339 | ||
340 | oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size); | |
341 | oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size); | |
342 | oehdr.put_e_phnum(this->segment_header_->data_size() | |
343 | / elfcpp::Elf_sizes<size>::phdr_size); | |
344 | oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size); | |
345 | oehdr.put_e_shnum(this->section_header_->data_size() | |
346 | / elfcpp::Elf_sizes<size>::shdr_size); | |
347 | oehdr.put_e_shstrndx(this->shstrtab_->shndx()); | |
348 | ||
349 | of->write_output_view(0, ehdr_size, view); | |
54dc6425 ILT |
350 | } |
351 | ||
a2fb1b05 ILT |
352 | // Output_section methods. |
353 | ||
354 | // Construct an Output_section. NAME will point into a Stringpool. | |
355 | ||
356 | Output_section::Output_section(const char* name, elfcpp::Elf_Word type, | |
61ba1cf9 | 357 | elfcpp::Elf_Xword flags, unsigned int shndx) |
a2fb1b05 | 358 | : name_(name), |
a2fb1b05 ILT |
359 | addralign_(0), |
360 | entsize_(0), | |
a2fb1b05 ILT |
361 | link_(0), |
362 | info_(0), | |
363 | type_(type), | |
61ba1cf9 ILT |
364 | flags_(flags), |
365 | shndx_(shndx) | |
a2fb1b05 ILT |
366 | { |
367 | } | |
368 | ||
54dc6425 ILT |
369 | Output_section::~Output_section() |
370 | { | |
371 | } | |
372 | ||
a2fb1b05 ILT |
373 | // Add an input section to an Output_section. We don't keep track of |
374 | // input sections for an Output_section. Instead, each Object keeps | |
375 | // track of the Output_section for each of its input sections. | |
376 | ||
377 | template<int size, bool big_endian> | |
378 | off_t | |
379 | Output_section::add_input_section(Object* object, const char* secname, | |
380 | const elfcpp::Shdr<size, big_endian>& shdr) | |
381 | { | |
382 | elfcpp::Elf_Xword addralign = shdr.get_sh_addralign(); | |
383 | if ((addralign & (addralign - 1)) != 0) | |
384 | { | |
385 | fprintf(stderr, _("%s: %s: invalid alignment %lu for section \"%s\"\n"), | |
386 | program_name, object->name().c_str(), | |
387 | static_cast<unsigned long>(addralign), secname); | |
388 | gold_exit(false); | |
389 | } | |
a2fb1b05 ILT |
390 | |
391 | if (addralign > this->addralign_) | |
392 | this->addralign_ = addralign; | |
393 | ||
75f65a3e | 394 | off_t ssize = this->data_size(); |
54dc6425 | 395 | ssize = (ssize + addralign - 1) &~ (addralign - 1); |
a2fb1b05 | 396 | |
75f65a3e ILT |
397 | // SHF_TLS/SHT_NOBITS sections are handled specially: they are |
398 | // treated as having no size and taking up no space. We only use | |
399 | // the real size when setting the pt_memsz field of the PT_TLS | |
400 | // segment. | |
401 | if ((this->flags_ & elfcpp::SHF_TLS) == 0 | |
402 | || this->type_ != elfcpp::SHT_NOBITS) | |
403 | this->set_data_size(ssize + shdr.get_sh_size()); | |
54dc6425 | 404 | |
61ba1cf9 ILT |
405 | return ssize; |
406 | } | |
407 | ||
408 | // Write the section header to *OSHDR. | |
409 | ||
410 | template<int size, bool big_endian> | |
411 | void | |
412 | Output_section::write_header(const Stringpool* secnamepool, | |
413 | elfcpp::Shdr_write<size, big_endian>* oshdr) const | |
414 | { | |
415 | oshdr->put_sh_name(secnamepool->get_offset(this->name_)); | |
416 | oshdr->put_sh_type(this->type_); | |
417 | oshdr->put_sh_flags(this->flags_); | |
418 | oshdr->put_sh_addr(this->address()); | |
419 | oshdr->put_sh_offset(this->offset()); | |
420 | oshdr->put_sh_size(this->data_size()); | |
421 | oshdr->put_sh_link(this->link_); | |
422 | oshdr->put_sh_info(this->info_); | |
423 | oshdr->put_sh_addralign(this->addralign_); | |
424 | oshdr->put_sh_entsize(this->entsize_); | |
a2fb1b05 ILT |
425 | } |
426 | ||
75f65a3e ILT |
427 | // Output_section_symtab methods. |
428 | ||
61ba1cf9 ILT |
429 | Output_section_symtab::Output_section_symtab(const char* name, off_t size, |
430 | unsigned int shndx) | |
431 | : Output_section(name, elfcpp::SHT_SYMTAB, 0, shndx) | |
75f65a3e ILT |
432 | { |
433 | this->set_data_size(size); | |
434 | } | |
435 | ||
436 | // Output_section_strtab methods. | |
437 | ||
438 | Output_section_strtab::Output_section_strtab(const char* name, | |
61ba1cf9 ILT |
439 | Stringpool* contents, |
440 | unsigned int shndx) | |
441 | : Output_section(name, elfcpp::SHT_STRTAB, 0, shndx), | |
75f65a3e ILT |
442 | contents_(contents) |
443 | { | |
61ba1cf9 | 444 | this->set_data_size(contents->get_strtab_size()); |
75f65a3e ILT |
445 | } |
446 | ||
447 | void | |
61ba1cf9 | 448 | Output_section_strtab::do_write(Output_file* of) |
75f65a3e | 449 | { |
61ba1cf9 | 450 | this->contents_->write(of, this->offset()); |
75f65a3e ILT |
451 | } |
452 | ||
a2fb1b05 ILT |
453 | // Output segment methods. |
454 | ||
455 | Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) | |
54dc6425 | 456 | : output_data_(), |
75f65a3e | 457 | output_bss_(), |
a2fb1b05 ILT |
458 | vaddr_(0), |
459 | paddr_(0), | |
460 | memsz_(0), | |
461 | align_(0), | |
462 | offset_(0), | |
463 | filesz_(0), | |
464 | type_(type), | |
465 | flags_(flags) | |
466 | { | |
467 | } | |
468 | ||
469 | // Add an Output_section to an Output_segment. | |
470 | ||
471 | void | |
75f65a3e ILT |
472 | Output_segment::add_output_section(Output_section* os, |
473 | elfcpp::Elf_Word seg_flags) | |
a2fb1b05 | 474 | { |
75f65a3e ILT |
475 | assert((os->flags() & elfcpp::SHF_ALLOC) != 0); |
476 | ||
477 | // Update the segment flags and alignment. | |
478 | this->flags_ |= seg_flags; | |
479 | uint64_t addralign = os->addralign(); | |
480 | if (addralign > this->align_) | |
481 | this->align_ = addralign; | |
482 | ||
483 | Output_segment::Output_data_list* pdl; | |
484 | if (os->type() == elfcpp::SHT_NOBITS) | |
485 | pdl = &this->output_bss_; | |
486 | else | |
487 | pdl = &this->output_data_; | |
54dc6425 | 488 | |
a2fb1b05 ILT |
489 | // So that PT_NOTE segments will work correctly, we need to ensure |
490 | // that all SHT_NOTE sections are adjacent. This will normally | |
491 | // happen automatically, because all the SHT_NOTE input sections | |
492 | // will wind up in the same output section. However, it is possible | |
493 | // for multiple SHT_NOTE input sections to have different section | |
494 | // flags, and thus be in different output sections, but for the | |
495 | // different section flags to map into the same segment flags and | |
496 | // thus the same output segment. | |
54dc6425 ILT |
497 | |
498 | // Note that while there may be many input sections in an output | |
499 | // section, there are normally only a few output sections in an | |
500 | // output segment. This loop is expected to be fast. | |
501 | ||
61ba1cf9 | 502 | if (os->type() == elfcpp::SHT_NOTE && !pdl->empty()) |
a2fb1b05 | 503 | { |
75f65a3e ILT |
504 | Layout::Data_list::iterator p = pdl->end(); |
505 | do | |
54dc6425 | 506 | { |
75f65a3e | 507 | --p; |
54dc6425 ILT |
508 | if ((*p)->is_section_type(elfcpp::SHT_NOTE)) |
509 | { | |
510 | ++p; | |
75f65a3e | 511 | pdl->insert(p, os); |
54dc6425 ILT |
512 | return; |
513 | } | |
514 | } | |
75f65a3e | 515 | while (p != pdl->begin()); |
54dc6425 ILT |
516 | } |
517 | ||
518 | // Similarly, so that PT_TLS segments will work, we need to group | |
75f65a3e ILT |
519 | // SHF_TLS sections. An SHF_TLS/SHT_NOBITS section is a special |
520 | // case: we group the SHF_TLS/SHT_NOBITS sections right after the | |
521 | // SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS | |
522 | // correctly. | |
61ba1cf9 | 523 | if ((os->flags() & elfcpp::SHF_TLS) != 0 && !this->output_data_.empty()) |
54dc6425 | 524 | { |
75f65a3e ILT |
525 | pdl = &this->output_data_; |
526 | bool nobits = os->type() == elfcpp::SHT_NOBITS; | |
527 | Layout::Data_list::iterator p = pdl->end(); | |
528 | do | |
a2fb1b05 | 529 | { |
75f65a3e ILT |
530 | --p; |
531 | if ((*p)->is_section_flag_set(elfcpp::SHF_TLS) | |
532 | && (nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS))) | |
a2fb1b05 ILT |
533 | { |
534 | ++p; | |
75f65a3e | 535 | pdl->insert(p, os); |
a2fb1b05 ILT |
536 | return; |
537 | } | |
538 | } | |
75f65a3e | 539 | while (p != pdl->begin()); |
a2fb1b05 ILT |
540 | } |
541 | ||
75f65a3e ILT |
542 | pdl->push_back(os); |
543 | } | |
544 | ||
545 | // Add an Output_data (which is not an Output_section) to the start of | |
546 | // a segment. | |
547 | ||
548 | void | |
549 | Output_segment::add_initial_output_data(Output_data* od) | |
550 | { | |
551 | uint64_t addralign = od->addralign(); | |
552 | if (addralign > this->align_) | |
553 | this->align_ = addralign; | |
554 | ||
555 | this->output_data_.push_front(od); | |
556 | } | |
557 | ||
558 | // Return the maximum alignment of the Output_data in Output_segment. | |
559 | // We keep this up to date as we add Output_sections and Output_data. | |
560 | ||
561 | uint64_t | |
562 | Output_segment::max_data_align() const | |
563 | { | |
564 | return this->align_; | |
565 | } | |
566 | ||
567 | // Set the section addresses for an Output_segment. ADDR is the | |
568 | // address and *POFF is the file offset. Return the address of the | |
569 | // immediately following segment. Update *POFF. | |
570 | ||
571 | uint64_t | |
572 | Output_segment::set_section_addresses(uint64_t addr, off_t* poff) | |
573 | { | |
574 | assert(this->type_ == elfcpp::PT_LOAD); | |
575 | ||
576 | this->vaddr_ = addr; | |
577 | this->paddr_ = addr; | |
578 | ||
579 | off_t orig_off = *poff; | |
580 | this->offset_ = orig_off; | |
581 | ||
582 | addr = this->set_section_list_addresses(&this->output_data_, addr, poff); | |
583 | this->filesz_ = *poff - orig_off; | |
584 | ||
585 | off_t off = *poff; | |
586 | ||
61ba1cf9 ILT |
587 | uint64_t ret = this->set_section_list_addresses(&this->output_bss_, addr, |
588 | poff); | |
75f65a3e ILT |
589 | this->memsz_ = *poff - orig_off; |
590 | ||
591 | // Ignore the file offset adjustments made by the BSS Output_data | |
592 | // objects. | |
593 | *poff = off; | |
61ba1cf9 ILT |
594 | |
595 | return ret; | |
75f65a3e ILT |
596 | } |
597 | ||
598 | // Set the addresses in a list of Output_data structures. | |
599 | ||
600 | uint64_t | |
601 | Output_segment::set_section_list_addresses(Output_data_list* pdl, | |
602 | uint64_t addr, off_t* poff) | |
603 | { | |
604 | off_t off = *poff; | |
605 | ||
606 | for (Output_data_list::iterator p = pdl->begin(); | |
607 | p != pdl->end(); | |
608 | ++p) | |
609 | { | |
610 | uint64_t addralign = (*p)->addralign(); | |
611 | addr = (addr + addralign - 1) & ~ (addralign - 1); | |
612 | off = (off + addralign - 1) & ~ (addralign - 1); | |
613 | (*p)->set_address(addr, off); | |
614 | ||
615 | uint64_t size = (*p)->data_size(); | |
616 | addr += size; | |
617 | off += size; | |
618 | } | |
619 | ||
620 | *poff = off; | |
621 | return addr; | |
622 | } | |
623 | ||
624 | // For a non-PT_LOAD segment, set the offset from the sections, if | |
625 | // any. | |
626 | ||
627 | void | |
628 | Output_segment::set_offset() | |
629 | { | |
630 | assert(this->type_ != elfcpp::PT_LOAD); | |
631 | ||
632 | if (this->output_data_.empty() && this->output_bss_.empty()) | |
633 | { | |
634 | this->vaddr_ = 0; | |
635 | this->paddr_ = 0; | |
636 | this->memsz_ = 0; | |
637 | this->align_ = 0; | |
638 | this->offset_ = 0; | |
639 | this->filesz_ = 0; | |
640 | return; | |
641 | } | |
642 | ||
643 | const Output_data* first; | |
644 | if (this->output_data_.empty()) | |
645 | first = this->output_bss_.front(); | |
646 | else | |
647 | first = this->output_data_.front(); | |
648 | this->vaddr_ = first->address(); | |
649 | this->paddr_ = this->vaddr_; | |
650 | this->offset_ = first->offset(); | |
651 | ||
652 | if (this->output_data_.empty()) | |
653 | this->filesz_ = 0; | |
654 | else | |
655 | { | |
656 | const Output_data* last_data = this->output_data_.back(); | |
657 | this->filesz_ = (last_data->address() | |
658 | + last_data->data_size() | |
659 | - this->vaddr_); | |
660 | } | |
661 | ||
662 | const Output_data* last; | |
663 | if (this->output_bss_.empty()) | |
664 | last = this->output_data_.back(); | |
665 | else | |
666 | last = this->output_bss_.back(); | |
667 | this->memsz_ = (last->address() | |
668 | + last->data_size() | |
669 | - this->vaddr_); | |
670 | ||
671 | // this->align_ was set as we added items. | |
672 | } | |
673 | ||
674 | // Return the number of Output_sections in an Output_segment. | |
675 | ||
676 | unsigned int | |
677 | Output_segment::output_section_count() const | |
678 | { | |
679 | return (this->output_section_count_list(&this->output_data_) | |
680 | + this->output_section_count_list(&this->output_bss_)); | |
681 | } | |
682 | ||
683 | // Return the number of Output_sections in an Output_data_list. | |
684 | ||
685 | unsigned int | |
686 | Output_segment::output_section_count_list(const Output_data_list* pdl) const | |
687 | { | |
688 | unsigned int count = 0; | |
689 | for (Output_data_list::const_iterator p = pdl->begin(); | |
690 | p != pdl->end(); | |
691 | ++p) | |
692 | { | |
693 | if ((*p)->is_section()) | |
694 | ++count; | |
695 | } | |
696 | return count; | |
a2fb1b05 ILT |
697 | } |
698 | ||
61ba1cf9 ILT |
699 | // Write the segment data into *OPHDR. |
700 | ||
701 | template<int size, bool big_endian> | |
702 | void | |
703 | Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) const | |
704 | { | |
705 | ophdr->put_p_type(this->type_); | |
706 | ophdr->put_p_offset(this->offset_); | |
707 | ophdr->put_p_vaddr(this->vaddr_); | |
708 | ophdr->put_p_paddr(this->paddr_); | |
709 | ophdr->put_p_filesz(this->filesz_); | |
710 | ophdr->put_p_memsz(this->memsz_); | |
711 | ophdr->put_p_flags(this->flags_); | |
712 | ophdr->put_p_align(this->align_); | |
713 | } | |
714 | ||
715 | // Write the section headers into V. | |
716 | ||
717 | template<int size, bool big_endian> | |
718 | unsigned char* | |
719 | Output_segment::write_section_headers(const Stringpool* secnamepool, | |
5482377d ILT |
720 | unsigned char* v |
721 | ACCEPT_SIZE_ENDIAN) const | |
722 | { | |
723 | v = this->write_section_headers_list SELECT_SIZE_ENDIAN_NAME ( | |
724 | secnamepool, &this->output_data_, v SELECT_SIZE_ENDIAN(size, big_endian)); | |
725 | v = this->write_section_headers_list SELECT_SIZE_ENDIAN_NAME ( | |
726 | secnamepool, &this->output_bss_, v SELECT_SIZE_ENDIAN(size, big_endian)); | |
61ba1cf9 ILT |
727 | return v; |
728 | } | |
729 | ||
730 | template<int size, bool big_endian> | |
731 | unsigned char* | |
732 | Output_segment::write_section_headers_list(const Stringpool* secnamepool, | |
733 | const Output_data_list* pdl, | |
5482377d ILT |
734 | unsigned char* v |
735 | ACCEPT_SIZE_ENDIAN) const | |
61ba1cf9 ILT |
736 | { |
737 | const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size; | |
738 | for (Output_data_list::const_iterator p = pdl->begin(); | |
739 | p != pdl->end(); | |
740 | ++p) | |
741 | { | |
742 | if ((*p)->is_section()) | |
743 | { | |
5482377d | 744 | const Output_section* ps = static_cast<const Output_section*>(*p); |
61ba1cf9 ILT |
745 | elfcpp::Shdr_write<size, big_endian> oshdr(v); |
746 | ps->write_header(secnamepool, &oshdr); | |
747 | v += shdr_size; | |
748 | } | |
749 | } | |
750 | return v; | |
751 | } | |
752 | ||
a2fb1b05 ILT |
753 | // Output_file methods. |
754 | ||
61ba1cf9 ILT |
755 | Output_file::Output_file(const General_options& options) |
756 | : options_(options), | |
757 | name_(options.output_file_name()), | |
758 | o_(-1), | |
759 | file_size_(0), | |
760 | base_(NULL) | |
761 | { | |
762 | } | |
763 | ||
764 | // Open the output file. | |
765 | ||
a2fb1b05 | 766 | void |
61ba1cf9 | 767 | Output_file::open(off_t file_size) |
a2fb1b05 | 768 | { |
61ba1cf9 ILT |
769 | this->file_size_ = file_size; |
770 | ||
771 | int mode = this->options_.is_relocatable() ? 0666 : 0777; | |
772 | int o = ::open(this->name_, O_RDWR | O_CREAT | O_TRUNC, mode); | |
773 | if (o < 0) | |
774 | { | |
775 | fprintf(stderr, _("%s: %s: open: %s\n"), | |
776 | program_name, this->name_, strerror(errno)); | |
777 | gold_exit(false); | |
778 | } | |
779 | this->o_ = o; | |
780 | ||
781 | // Write out one byte to make the file the right size. | |
782 | if (::lseek(o, file_size - 1, SEEK_SET) < 0) | |
783 | { | |
784 | fprintf(stderr, _("%s: %s: lseek: %s\n"), | |
785 | program_name, this->name_, strerror(errno)); | |
786 | gold_exit(false); | |
787 | } | |
788 | char b = 0; | |
789 | if (::write(o, &b, 1) != 1) | |
790 | { | |
791 | fprintf(stderr, _("%s: %s: write: %s\n"), | |
792 | program_name, this->name_, strerror(errno)); | |
793 | gold_exit(false); | |
794 | } | |
795 | ||
796 | // Map the file into memory. | |
797 | void* base = ::mmap(NULL, file_size, PROT_READ | PROT_WRITE, | |
798 | MAP_SHARED, o, 0); | |
799 | if (base == MAP_FAILED) | |
800 | { | |
801 | fprintf(stderr, _("%s: %s: mmap: %s\n"), | |
802 | program_name, this->name_, strerror(errno)); | |
803 | gold_exit(false); | |
804 | } | |
805 | this->base_ = static_cast<unsigned char*>(base); | |
806 | } | |
807 | ||
808 | // Close the output file. | |
809 | ||
810 | void | |
811 | Output_file::close() | |
812 | { | |
813 | if (::munmap(this->base_, this->file_size_) < 0) | |
814 | { | |
815 | fprintf(stderr, _("%s: %s: munmap: %s\n"), | |
816 | program_name, this->name_, strerror(errno)); | |
817 | gold_exit(false); | |
818 | } | |
819 | this->base_ = NULL; | |
820 | ||
821 | if (::close(this->o_) < 0) | |
822 | { | |
823 | fprintf(stderr, _("%s: %s: close: %s\n"), | |
824 | program_name, this->name_, strerror(errno)); | |
825 | gold_exit(false); | |
826 | } | |
827 | this->o_ = -1; | |
a2fb1b05 ILT |
828 | } |
829 | ||
830 | // Instantiate the templates we need. We could use the configure | |
831 | // script to restrict this to only the ones for implemented targets. | |
832 | ||
833 | template | |
834 | off_t | |
835 | Output_section::add_input_section<32, false>( | |
836 | Object* object, | |
837 | const char* secname, | |
838 | const elfcpp::Shdr<32, false>& shdr); | |
839 | ||
840 | template | |
841 | off_t | |
842 | Output_section::add_input_section<32, true>( | |
843 | Object* object, | |
844 | const char* secname, | |
845 | const elfcpp::Shdr<32, true>& shdr); | |
846 | ||
847 | template | |
848 | off_t | |
849 | Output_section::add_input_section<64, false>( | |
850 | Object* object, | |
851 | const char* secname, | |
852 | const elfcpp::Shdr<64, false>& shdr); | |
853 | ||
854 | template | |
855 | off_t | |
856 | Output_section::add_input_section<64, true>( | |
857 | Object* object, | |
858 | const char* secname, | |
859 | const elfcpp::Shdr<64, true>& shdr); | |
860 | ||
861 | } // End namespace gold. |