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