forked from bminor/binutils-gdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoutput.h
4928 lines (4168 loc) · 146 KB
/
output.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// output.h -- manage the output file for gold -*- C++ -*-
// Copyright (C) 2006-2025 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <[email protected]>.
// This file is part of gold.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
#ifndef GOLD_OUTPUT_H
#define GOLD_OUTPUT_H
#include <algorithm>
#include <list>
#include <vector>
#include "elfcpp.h"
#include "mapfile.h"
#include "layout.h"
#include "reloc-types.h"
namespace gold
{
class General_options;
class Object;
class Symbol;
class Output_merge_base;
class Output_section;
class Relocatable_relocs;
class Target;
template<int size, bool big_endian>
class Sized_target;
template<int size, bool big_endian>
class Sized_relobj;
template<int size, bool big_endian>
class Sized_relobj_file;
// This class represents the output file.
class Output_file
{
public:
Output_file(const char* name);
// Indicate that this is a temporary file which should not be
// output.
void
set_is_temporary()
{ this->is_temporary_ = true; }
// Try to open an existing file. Returns false if the file doesn't
// exist, has a size of 0 or can't be mmaped. This method is
// thread-unsafe. If BASE_NAME is not NULL, use the contents of
// that file as the base for incremental linking.
bool
open_base_file(const char* base_name, bool writable);
// Open the output file. FILE_SIZE is the final size of the file.
// If the file already exists, it is deleted/truncated. This method
// is thread-unsafe.
void
open(off_t file_size);
// Resize the output file. This method is thread-unsafe.
void
resize(off_t file_size);
// Close the output file (flushing all buffered data) and make sure
// there are no errors. This method is thread-unsafe.
void
close();
// Return the size of this file.
off_t
filesize()
{ return this->file_size_; }
// Return the name of this file.
const char*
filename()
{ return this->name_; }
// We currently always use mmap which makes the view handling quite
// simple. In the future we may support other approaches.
// Write data to the output file.
void
write(off_t offset, const void* data, size_t len)
{ memcpy(this->base_ + offset, data, len); }
// Get a buffer to use to write to the file, given the offset into
// the file and the size.
unsigned char*
get_output_view(off_t start, size_t size)
{
gold_assert(start >= 0
&& start + static_cast<off_t>(size) <= this->file_size_);
return this->base_ + start;
}
// VIEW must have been returned by get_output_view. Write the
// buffer to the file, passing in the offset and the size.
void
write_output_view(off_t, size_t, unsigned char*)
{ }
// Get a read/write buffer. This is used when we want to write part
// of the file, read it in, and write it again.
unsigned char*
get_input_output_view(off_t start, size_t size)
{ return this->get_output_view(start, size); }
// Write a read/write buffer back to the file.
void
write_input_output_view(off_t, size_t, unsigned char*)
{ }
// Get a read buffer. This is used when we just want to read part
// of the file back it in.
const unsigned char*
get_input_view(off_t start, size_t size)
{ return this->get_output_view(start, size); }
// Release a read bfufer.
void
free_input_view(off_t, size_t, const unsigned char*)
{ }
private:
// Map the file into memory or, if that fails, allocate anonymous
// memory.
void
map();
// Allocate anonymous memory for the file.
bool
map_anonymous();
// Map the file into memory.
bool
map_no_anonymous(bool);
// Unmap the file from memory (and flush to disk buffers).
void
unmap();
// File name.
const char* name_;
// File descriptor.
int o_;
// File size.
off_t file_size_;
// Base of file mapped into memory.
unsigned char* base_;
// True iff base_ points to a memory buffer rather than an output file.
bool map_is_anonymous_;
// True if base_ was allocated using new rather than mmap.
bool map_is_allocated_;
// True if this is a temporary file which should not be output.
bool is_temporary_;
};
// An abtract class for data which has to go into the output file.
class Output_data
{
public:
explicit Output_data()
: address_(0), data_size_(0), offset_(-1),
is_address_valid_(false), is_data_size_valid_(false),
is_offset_valid_(false), is_data_size_fixed_(false),
has_dynamic_reloc_(false)
{ }
virtual
~Output_data();
// Return the address. For allocated sections, this is only valid
// after Layout::finalize is finished.
uint64_t
address() const
{
gold_assert(this->is_address_valid_);
return this->address_;
}
// Return the size of the data. For allocated sections, this must
// be valid after Layout::finalize calls set_address, but need not
// be valid before then.
off_t
data_size() const
{
gold_assert(this->is_data_size_valid_);
return this->data_size_;
}
// Get the current data size.
off_t
current_data_size() const
{ return this->current_data_size_for_child(); }
// Return true if data size is fixed.
bool
is_data_size_fixed() const
{ return this->is_data_size_fixed_; }
// Return the file offset. This is only valid after
// Layout::finalize is finished. For some non-allocated sections,
// it may not be valid until near the end of the link.
off_t
offset() const
{
gold_assert(this->is_offset_valid_);
return this->offset_;
}
// Reset the address, file offset and data size. This essentially
// disables the sanity testing about duplicate and unknown settings.
void
reset_address_and_file_offset()
{
this->is_address_valid_ = false;
this->is_offset_valid_ = false;
if (!this->is_data_size_fixed_)
this->is_data_size_valid_ = false;
this->do_reset_address_and_file_offset();
}
// As above, but just for data size.
void
reset_data_size()
{
if (!this->is_data_size_fixed_)
this->is_data_size_valid_ = false;
}
// Return true if address and file offset already have reset values. In
// other words, calling reset_address_and_file_offset will not change them.
bool
address_and_file_offset_have_reset_values() const
{ return this->do_address_and_file_offset_have_reset_values(); }
// Return the required alignment.
uint64_t
addralign() const
{ return this->do_addralign(); }
// Return whether this has a load address.
bool
has_load_address() const
{ return this->do_has_load_address(); }
// Return the load address.
uint64_t
load_address() const
{ return this->do_load_address(); }
// Return whether this is an Output_section.
bool
is_section() const
{ return this->do_is_section(); }
// Return whether this is an Output_section of the specified type.
bool
is_section_type(elfcpp::Elf_Word stt) const
{ return this->do_is_section_type(stt); }
// Return whether this is an Output_section with the specified flag
// set.
bool
is_section_flag_set(elfcpp::Elf_Xword shf) const
{ return this->do_is_section_flag_set(shf); }
// Return the output section that this goes in, if there is one.
Output_section*
output_section()
{ return this->do_output_section(); }
const Output_section*
output_section() const
{ return this->do_output_section(); }
// Return the output section index, if there is an output section.
unsigned int
out_shndx() const
{ return this->do_out_shndx(); }
// Set the output section index, if this is an output section.
void
set_out_shndx(unsigned int shndx)
{ this->do_set_out_shndx(shndx); }
// Set the address and file offset of this data, and finalize the
// size of the data. This is called during Layout::finalize for
// allocated sections.
void
set_address_and_file_offset(uint64_t addr, off_t off)
{
this->set_address(addr);
this->set_file_offset(off);
this->finalize_data_size();
}
// Set the address.
void
set_address(uint64_t addr)
{
gold_assert(!this->is_address_valid_);
this->address_ = addr;
this->is_address_valid_ = true;
}
// Set the file offset.
void
set_file_offset(off_t off)
{
gold_assert(!this->is_offset_valid_);
this->offset_ = off;
this->is_offset_valid_ = true;
}
// Update the data size without finalizing it.
void
pre_finalize_data_size()
{
if (!this->is_data_size_valid_)
{
// Tell the child class to update the data size.
this->update_data_size();
}
}
// Finalize the data size.
void
finalize_data_size()
{
if (!this->is_data_size_valid_)
{
// Tell the child class to set the data size.
this->set_final_data_size();
gold_assert(this->is_data_size_valid_);
}
}
// Set the TLS offset. Called only for SHT_TLS sections.
void
set_tls_offset(uint64_t tls_base)
{ this->do_set_tls_offset(tls_base); }
// Return the TLS offset, relative to the base of the TLS segment.
// Valid only for SHT_TLS sections.
uint64_t
tls_offset() const
{ return this->do_tls_offset(); }
// Write the data to the output file. This is called after
// Layout::finalize is complete.
void
write(Output_file* file)
{ this->do_write(file); }
// This is called by Layout::finalize to note that the sizes of
// allocated sections must now be fixed.
static void
layout_complete()
{ Output_data::allocated_sizes_are_fixed = true; }
// Used to check that layout has been done.
static bool
is_layout_complete()
{ return Output_data::allocated_sizes_are_fixed; }
// Note that a dynamic reloc has been applied to this data.
void
add_dynamic_reloc()
{ this->has_dynamic_reloc_ = true; }
// Return whether a dynamic reloc has been applied.
bool
has_dynamic_reloc() const
{ return this->has_dynamic_reloc_; }
// Whether the address is valid.
bool
is_address_valid() const
{ return this->is_address_valid_; }
// Whether the file offset is valid.
bool
is_offset_valid() const
{ return this->is_offset_valid_; }
// Whether the data size is valid.
bool
is_data_size_valid() const
{ return this->is_data_size_valid_; }
// Print information to the map file.
void
print_to_mapfile(Mapfile* mapfile) const
{ return this->do_print_to_mapfile(mapfile); }
protected:
// Functions that child classes may or in some cases must implement.
// Write the data to the output file.
virtual void
do_write(Output_file*) = 0;
// Return the required alignment.
virtual uint64_t
do_addralign() const = 0;
// Return whether this has a load address.
virtual bool
do_has_load_address() const
{ return false; }
// Return the load address.
virtual uint64_t
do_load_address() const
{ gold_unreachable(); }
// Return whether this is an Output_section.
virtual bool
do_is_section() const
{ return false; }
// Return whether this is an Output_section of the specified type.
// This only needs to be implement by Output_section.
virtual bool
do_is_section_type(elfcpp::Elf_Word) const
{ return false; }
// Return whether this is an Output_section with the specific flag
// set. This only needs to be implemented by Output_section.
virtual bool
do_is_section_flag_set(elfcpp::Elf_Xword) const
{ return false; }
// Return the output section, if there is one.
virtual Output_section*
do_output_section()
{ return NULL; }
virtual const Output_section*
do_output_section() const
{ return NULL; }
// Return the output section index, if there is an output section.
virtual unsigned int
do_out_shndx() const
{ gold_unreachable(); }
// Set the output section index, if this is an output section.
virtual void
do_set_out_shndx(unsigned int)
{ gold_unreachable(); }
// This is a hook for derived classes to set the preliminary data size.
// This is called by pre_finalize_data_size, normally called during
// Layout::finalize, before the section address is set, and is used
// during an incremental update, when we need to know the size of a
// section before allocating space in the output file. For classes
// where the current data size is up to date, this default version of
// the method can be inherited.
virtual void
update_data_size()
{ }
// This is a hook for derived classes to set the data size. This is
// called by finalize_data_size, normally called during
// Layout::finalize, when the section address is set.
virtual void
set_final_data_size()
{ gold_unreachable(); }
// A hook for resetting the address and file offset.
virtual void
do_reset_address_and_file_offset()
{ }
// Return true if address and file offset already have reset values. In
// other words, calling reset_address_and_file_offset will not change them.
// A child class overriding do_reset_address_and_file_offset may need to
// also override this.
virtual bool
do_address_and_file_offset_have_reset_values() const
{ return !this->is_address_valid_ && !this->is_offset_valid_; }
// Set the TLS offset. Called only for SHT_TLS sections.
virtual void
do_set_tls_offset(uint64_t)
{ gold_unreachable(); }
// Return the TLS offset, relative to the base of the TLS segment.
// Valid only for SHT_TLS sections.
virtual uint64_t
do_tls_offset() const
{ gold_unreachable(); }
// Print to the map file. This only needs to be implemented by
// classes which may appear in a PT_LOAD segment.
virtual void
do_print_to_mapfile(Mapfile*) const
{ gold_unreachable(); }
// Functions that child classes may call.
// Reset the address. The Output_section class needs this when an
// SHF_ALLOC input section is added to an output section which was
// formerly not SHF_ALLOC.
void
mark_address_invalid()
{ this->is_address_valid_ = false; }
// Set the size of the data.
void
set_data_size(off_t data_size)
{
gold_assert(!this->is_data_size_valid_
&& !this->is_data_size_fixed_);
this->data_size_ = data_size;
this->is_data_size_valid_ = true;
}
// Fix the data size. Once it is fixed, it cannot be changed
// and the data size remains always valid.
void
fix_data_size()
{
gold_assert(this->is_data_size_valid_);
this->is_data_size_fixed_ = true;
}
// Get the current data size--this is for the convenience of
// sections which build up their size over time.
off_t
current_data_size_for_child() const
{ return this->data_size_; }
// Set the current data size--this is for the convenience of
// sections which build up their size over time.
void
set_current_data_size_for_child(off_t data_size)
{
gold_assert(!this->is_data_size_valid_);
this->data_size_ = data_size;
}
// Return default alignment for the target size.
static uint64_t
default_alignment();
// Return default alignment for a specified size--32 or 64.
static uint64_t
default_alignment_for_size(int size);
private:
Output_data(const Output_data&);
Output_data& operator=(const Output_data&);
// This is used for verification, to make sure that we don't try to
// change any sizes of allocated sections after we set the section
// addresses.
static bool allocated_sizes_are_fixed;
// Memory address in output file.
uint64_t address_;
// Size of data in output file.
off_t data_size_;
// File offset of contents in output file.
off_t offset_;
// Whether address_ is valid.
bool is_address_valid_ : 1;
// Whether data_size_ is valid.
bool is_data_size_valid_ : 1;
// Whether offset_ is valid.
bool is_offset_valid_ : 1;
// Whether data size is fixed.
bool is_data_size_fixed_ : 1;
// Whether any dynamic relocs have been applied to this section.
bool has_dynamic_reloc_ : 1;
};
// Output the section headers.
class Output_section_headers : public Output_data
{
public:
Output_section_headers(const Layout*,
const Layout::Segment_list*,
const Layout::Section_list*,
const Layout::Section_list*,
const Stringpool*,
const Output_section*);
protected:
// Write the data to the file.
void
do_write(Output_file*);
// Return the required alignment.
uint64_t
do_addralign() const
{ return Output_data::default_alignment(); }
// Write to a map file.
void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** section headers")); }
// Update the data size.
void
update_data_size()
{ this->set_data_size(this->do_size()); }
// Set final data size.
void
set_final_data_size()
{ this->set_data_size(this->do_size()); }
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
void
do_sized_write(Output_file*);
// Compute data size.
off_t
do_size() const;
const Layout* layout_;
const Layout::Segment_list* segment_list_;
const Layout::Section_list* section_list_;
const Layout::Section_list* unattached_section_list_;
const Stringpool* secnamepool_;
const Output_section* shstrtab_section_;
};
// Output the segment headers.
class Output_segment_headers : public Output_data
{
public:
Output_segment_headers(const Layout::Segment_list& segment_list);
protected:
// Write the data to the file.
void
do_write(Output_file*);
// Return the required alignment.
uint64_t
do_addralign() const
{ return Output_data::default_alignment(); }
// Write to a map file.
void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** segment headers")); }
// Set final data size.
void
set_final_data_size()
{ this->set_data_size(this->do_size()); }
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
void
do_sized_write(Output_file*);
// Compute the current size.
off_t
do_size() const;
const Layout::Segment_list& segment_list_;
};
// Output the ELF file header.
class Output_file_header : public Output_data
{
public:
Output_file_header(Target*,
const Symbol_table*,
const Output_segment_headers*);
// Add information about the section headers. We lay out the ELF
// file header before we create the section headers.
void set_section_info(const Output_section_headers*,
const Output_section* shstrtab);
protected:
// Write the data to the file.
void
do_write(Output_file*);
// Return the required alignment.
uint64_t
do_addralign() const
{ return Output_data::default_alignment(); }
// Write to a map file.
void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** file header")); }
// Set final data size.
void
set_final_data_size(void)
{ this->set_data_size(this->do_size()); }
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
void
do_sized_write(Output_file*);
// Return the value to use for the entry address.
template<int size>
typename elfcpp::Elf_types<size>::Elf_Addr
entry();
// Compute the current data size.
off_t
do_size() const;
Target* target_;
const Symbol_table* symtab_;
const Output_segment_headers* segment_header_;
const Output_section_headers* section_header_;
const Output_section* shstrtab_;
};
// Output sections are mainly comprised of input sections. However,
// there are cases where we have data to write out which is not in an
// input section. Output_section_data is used in such cases. This is
// an abstract base class.
class Output_section_data : public Output_data
{
public:
Output_section_data(off_t data_size, uint64_t addralign,
bool is_data_size_fixed)
: Output_data(), output_section_(NULL), addralign_(addralign)
{
this->set_data_size(data_size);
if (is_data_size_fixed)
this->fix_data_size();
}
Output_section_data(uint64_t addralign)
: Output_data(), output_section_(NULL), addralign_(addralign)
{ }
// Return the output section.
Output_section*
output_section()
{ return this->output_section_; }
const Output_section*
output_section() const
{ return this->output_section_; }
// Record the output section.
void
set_output_section(Output_section* os);
// Add an input section, for SHF_MERGE sections. This returns true
// if the section was handled.
bool
add_input_section(Relobj* object, unsigned int shndx)
{ return this->do_add_input_section(object, shndx); }
// Given an input OBJECT, an input section index SHNDX within that
// object, and an OFFSET relative to the start of that input
// section, return whether or not the corresponding offset within
// the output section is known. If this function returns true, it
// sets *POUTPUT to the output offset. The value -1 indicates that
// this input offset is being discarded.
bool
output_offset(const Relobj* object, unsigned int shndx,
section_offset_type offset,
section_offset_type* poutput) const
{ return this->do_output_offset(object, shndx, offset, poutput); }
// Write the contents to a buffer. This is used for sections which
// require postprocessing, such as compression.
void
write_to_buffer(unsigned char* buffer)
{ this->do_write_to_buffer(buffer); }
// Print merge stats to stderr. This should only be called for
// SHF_MERGE sections.
void
print_merge_stats(const char* section_name)
{ this->do_print_merge_stats(section_name); }
protected:
// The child class must implement do_write.
// The child class may implement specific adjustments to the output
// section.
virtual void
do_adjust_output_section(Output_section*)
{ }
// May be implemented by child class. Return true if the section
// was handled.
virtual bool
do_add_input_section(Relobj*, unsigned int)
{ gold_unreachable(); }
// The child class may implement output_offset.
virtual bool
do_output_offset(const Relobj*, unsigned int, section_offset_type,
section_offset_type*) const
{ return false; }
// The child class may implement write_to_buffer. Most child
// classes can not appear in a compressed section, and they do not
// implement this.
virtual void
do_write_to_buffer(unsigned char*)
{ gold_unreachable(); }
// Print merge statistics.
virtual void
do_print_merge_stats(const char*)
{ gold_unreachable(); }
// Return the required alignment.
uint64_t
do_addralign() const
{ return this->addralign_; }
// Return the output section.
Output_section*
do_output_section()
{ return this->output_section_; }
const Output_section*
do_output_section() const
{ return this->output_section_; }
// Return the section index of the output section.
unsigned int
do_out_shndx() const;
// Set the alignment.
void
set_addralign(uint64_t addralign);
private:
// The output section for this section.
Output_section* output_section_;
// The required alignment.
uint64_t addralign_;
};
// Some Output_section_data classes build up their data step by step,
// rather than all at once. This class provides an interface for
// them.
class Output_section_data_build : public Output_section_data
{
public:
Output_section_data_build(uint64_t addralign)
: Output_section_data(addralign)
{ }
Output_section_data_build(off_t data_size, uint64_t addralign)
: Output_section_data(data_size, addralign, false)
{ }
// Set the current data size.
void
set_current_data_size(off_t data_size)
{ this->set_current_data_size_for_child(data_size); }
protected:
// Set the final data size.
virtual void
set_final_data_size()
{ this->set_data_size(this->current_data_size_for_child()); }
};
// A simple case of Output_data in which we have constant data to
// output.
class Output_data_const : public Output_section_data
{
public:
Output_data_const(const std::string& data, uint64_t addralign)
: Output_section_data(data.size(), addralign, true), data_(data)
{ }
Output_data_const(const char* p, off_t len, uint64_t addralign)
: Output_section_data(len, addralign, true), data_(p, len)
{ }
Output_data_const(const unsigned char* p, off_t len, uint64_t addralign)
: Output_section_data(len, addralign, true),
data_(reinterpret_cast<const char*>(p), len)
{ }
protected:
// Write the data to the output file.
void
do_write(Output_file*);
// Write the data to a buffer.
void
do_write_to_buffer(unsigned char* buffer)
{ memcpy(buffer, this->data_.data(), this->data_.size()); }
// Write to a map file.
void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** fill")); }
private:
std::string data_;
};
// Another version of Output_data with constant data, in which the
// buffer is allocated by the caller.
class Output_data_const_buffer : public Output_section_data
{
public:
Output_data_const_buffer(const unsigned char* p, off_t len,
uint64_t addralign, const char* map_name)
: Output_section_data(len, addralign, true),
p_(p), map_name_(map_name)
{ }
protected:
// Write the data the output file.
void
do_write(Output_file*);
// Write the data to a buffer.
void
do_write_to_buffer(unsigned char* buffer)
{ memcpy(buffer, this->p_, this->data_size()); }
// Write to a map file.
void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _(this->map_name_)); }
private:
// The data to output.
const unsigned char* p_;
// Name to use in a map file. Maps are a rarely used feature, but
// the space usage is minor as aren't very many of these objects.
const char* map_name_;
};
// A place holder for a fixed amount of data written out via some
// other mechanism.
class Output_data_fixed_space : public Output_section_data
{
public:
Output_data_fixed_space(off_t data_size, uint64_t addralign,
const char* map_name)
: Output_section_data(data_size, addralign, true),
map_name_(map_name)
{ }
protected:
// Write out the data--the actual data must be written out
// elsewhere.
void
do_write(Output_file*)
{ }
// Write to a map file.
void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _(this->map_name_)); }