-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathx86_64.cc
6432 lines (5740 loc) · 203 KB
/
x86_64.cc
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
// x86_64.cc -- x86_64 target support for gold.
// Copyright (C) 2006-2019 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.
#include "gold.h"
#include <cstring>
#include "elfcpp.h"
#include "dwarf.h"
#include "parameters.h"
#include "reloc.h"
#include "x86_64.h"
#include "object.h"
#include "symtab.h"
#include "layout.h"
#include "output.h"
#include "copy-relocs.h"
#include "target.h"
#include "target-reloc.h"
#include "target-select.h"
#include "tls.h"
#include "freebsd.h"
#include "nacl.h"
#include "gc.h"
#include "icf.h"
namespace
{
using namespace gold;
// A class to handle the .got.plt section.
class Output_data_got_plt_x86_64 : public Output_section_data_build
{
public:
Output_data_got_plt_x86_64(Layout* layout)
: Output_section_data_build(8),
layout_(layout)
{ }
Output_data_got_plt_x86_64(Layout* layout, off_t data_size)
: Output_section_data_build(data_size, 8),
layout_(layout)
{ }
protected:
// Write out the PLT data.
void
do_write(Output_file*);
// Write to a map file.
void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, "** GOT PLT"); }
private:
// A pointer to the Layout class, so that we can find the .dynamic
// section when we write out the GOT PLT section.
Layout* layout_;
};
// A class to handle the PLT data.
// This is an abstract base class that handles most of the linker details
// but does not know the actual contents of PLT entries. The derived
// classes below fill in those details.
template<int size>
class Output_data_plt_x86_64 : public Output_section_data
{
public:
typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, false> Reloc_section;
Output_data_plt_x86_64(Layout* layout, uint64_t addralign,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative)
: Output_section_data(addralign), tlsdesc_rel_(NULL),
irelative_rel_(NULL), got_(got), got_plt_(got_plt),
got_irelative_(got_irelative), count_(0), irelative_count_(0),
tlsdesc_got_offset_(-1U), free_list_()
{ this->init(layout); }
Output_data_plt_x86_64(Layout* layout, uint64_t plt_entry_size,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative,
unsigned int plt_count)
: Output_section_data((plt_count + 1) * plt_entry_size,
plt_entry_size, false),
tlsdesc_rel_(NULL), irelative_rel_(NULL), got_(got),
got_plt_(got_plt), got_irelative_(got_irelative), count_(plt_count),
irelative_count_(0), tlsdesc_got_offset_(-1U), free_list_()
{
this->init(layout);
// Initialize the free list and reserve the first entry.
this->free_list_.init((plt_count + 1) * plt_entry_size, false);
this->free_list_.remove(0, plt_entry_size);
}
// Initialize the PLT section.
void
init(Layout* layout);
// Add an entry to the PLT.
void
add_entry(Symbol_table*, Layout*, Symbol* gsym);
// Add an entry to the PLT for a local STT_GNU_IFUNC symbol.
unsigned int
add_local_ifunc_entry(Symbol_table* symtab, Layout*,
Sized_relobj_file<size, false>* relobj,
unsigned int local_sym_index);
// Add the relocation for a PLT entry.
void
add_relocation(Symbol_table*, Layout*, Symbol* gsym,
unsigned int got_offset);
// Add the reserved TLSDESC_PLT entry to the PLT.
void
reserve_tlsdesc_entry(unsigned int got_offset)
{ this->tlsdesc_got_offset_ = got_offset; }
// Return true if a TLSDESC_PLT entry has been reserved.
bool
has_tlsdesc_entry() const
{ return this->tlsdesc_got_offset_ != -1U; }
// Return the GOT offset for the reserved TLSDESC_PLT entry.
unsigned int
get_tlsdesc_got_offset() const
{ return this->tlsdesc_got_offset_; }
// Return the offset of the reserved TLSDESC_PLT entry.
unsigned int
get_tlsdesc_plt_offset() const
{
return ((this->count_ + this->irelative_count_ + 1)
* this->get_plt_entry_size());
}
// Return the .rela.plt section data.
Reloc_section*
rela_plt()
{ return this->rel_; }
// Return where the TLSDESC relocations should go.
Reloc_section*
rela_tlsdesc(Layout*);
// Return where the IRELATIVE relocations should go in the PLT
// relocations.
Reloc_section*
rela_irelative(Symbol_table*, Layout*);
// Return whether we created a section for IRELATIVE relocations.
bool
has_irelative_section() const
{ return this->irelative_rel_ != NULL; }
// Get count of regular PLT entries.
unsigned int
regular_count() const
{ return this->count_; }
// Return the total number of PLT entries.
unsigned int
entry_count() const
{ return this->count_ + this->irelative_count_; }
// Return the offset of the first non-reserved PLT entry.
unsigned int
first_plt_entry_offset()
{ return this->get_plt_entry_size(); }
// Return the size of a PLT entry.
unsigned int
get_plt_entry_size() const
{ return this->do_get_plt_entry_size(); }
// Reserve a slot in the PLT for an existing symbol in an incremental update.
void
reserve_slot(unsigned int plt_index)
{
this->free_list_.remove((plt_index + 1) * this->get_plt_entry_size(),
(plt_index + 2) * this->get_plt_entry_size());
}
// Return the PLT address to use for a global symbol.
uint64_t
address_for_global(const Symbol* sym)
{ return do_address_for_global(sym); }
// Return the PLT address to use for a local symbol.
uint64_t
address_for_local(const Relobj* obj, unsigned int symndx)
{ return do_address_for_local(obj, symndx); }
// Add .eh_frame information for the PLT.
void
add_eh_frame(Layout* layout)
{ this->do_add_eh_frame(layout); }
protected:
Output_data_got<64, false>*
got() const
{ return this->got_; }
Output_data_got_plt_x86_64*
got_plt() const
{ return this->got_plt_; }
Output_data_space*
got_irelative() const
{ return this->got_irelative_; }
// Fill in the first PLT entry.
void
fill_first_plt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
{ this->do_fill_first_plt_entry(pov, got_address, plt_address); }
// Fill in a normal PLT entry. Returns the offset into the entry that
// should be the initial GOT slot value.
unsigned int
fill_plt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
unsigned int got_offset,
unsigned int plt_offset,
unsigned int plt_index)
{
return this->do_fill_plt_entry(pov, got_address, plt_address,
got_offset, plt_offset, plt_index);
}
// Fill in the reserved TLSDESC PLT entry.
void
fill_tlsdesc_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
typename elfcpp::Elf_types<size>::Elf_Addr got_base,
unsigned int tlsdesc_got_offset,
unsigned int plt_offset)
{
this->do_fill_tlsdesc_entry(pov, got_address, plt_address, got_base,
tlsdesc_got_offset, plt_offset);
}
virtual unsigned int
do_get_plt_entry_size() const = 0;
virtual void
do_fill_first_plt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
typename elfcpp::Elf_types<size>::Elf_Addr plt_addr)
= 0;
virtual unsigned int
do_fill_plt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
unsigned int got_offset,
unsigned int plt_offset,
unsigned int plt_index) = 0;
virtual void
do_fill_tlsdesc_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
typename elfcpp::Elf_types<size>::Elf_Addr got_base,
unsigned int tlsdesc_got_offset,
unsigned int plt_offset) = 0;
// Return the PLT address to use for a global symbol.
virtual uint64_t
do_address_for_global(const Symbol* sym);
// Return the PLT address to use for a local symbol.
virtual uint64_t
do_address_for_local(const Relobj* obj, unsigned int symndx);
virtual void
do_add_eh_frame(Layout* layout) = 0;
void
do_adjust_output_section(Output_section* os);
// Write to a map file.
void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** PLT")); }
// The CIE of the .eh_frame unwind information for the PLT.
static const int plt_eh_frame_cie_size = 16;
static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size];
private:
// Set the final size.
void
set_final_data_size();
// Write out the PLT data.
void
do_write(Output_file*);
// The reloc section.
Reloc_section* rel_;
// The TLSDESC relocs, if necessary. These must follow the regular
// PLT relocs.
Reloc_section* tlsdesc_rel_;
// The IRELATIVE relocs, if necessary. These must follow the
// regular PLT relocations and the TLSDESC relocations.
Reloc_section* irelative_rel_;
// The .got section.
Output_data_got<64, false>* got_;
// The .got.plt section.
Output_data_got_plt_x86_64* got_plt_;
// The part of the .got.plt section used for IRELATIVE relocs.
Output_data_space* got_irelative_;
// The number of PLT entries.
unsigned int count_;
// Number of PLT entries with R_X86_64_IRELATIVE relocs. These
// follow the regular PLT entries.
unsigned int irelative_count_;
// Offset of the reserved TLSDESC_GOT entry when needed.
unsigned int tlsdesc_got_offset_;
// List of available regions within the section, for incremental
// update links.
Free_list free_list_;
};
template<int size>
class Output_data_plt_x86_64_standard : public Output_data_plt_x86_64<size>
{
public:
Output_data_plt_x86_64_standard(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative)
: Output_data_plt_x86_64<size>(layout, plt_entry_size,
got, got_plt, got_irelative)
{ }
Output_data_plt_x86_64_standard(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative,
unsigned int plt_count)
: Output_data_plt_x86_64<size>(layout, plt_entry_size,
got, got_plt, got_irelative,
plt_count)
{ }
protected:
virtual unsigned int
do_get_plt_entry_size() const
{ return plt_entry_size; }
virtual void
do_add_eh_frame(Layout* layout)
{
layout->add_eh_frame_for_plt(this,
this->plt_eh_frame_cie,
this->plt_eh_frame_cie_size,
plt_eh_frame_fde,
plt_eh_frame_fde_size);
}
virtual void
do_fill_first_plt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
typename elfcpp::Elf_types<size>::Elf_Addr plt_addr);
virtual unsigned int
do_fill_plt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
unsigned int got_offset,
unsigned int plt_offset,
unsigned int plt_index);
virtual void
do_fill_tlsdesc_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
typename elfcpp::Elf_types<size>::Elf_Addr got_base,
unsigned int tlsdesc_got_offset,
unsigned int plt_offset);
private:
// The size of an entry in the PLT.
static const int plt_entry_size = 16;
// The first entry in the PLT.
// From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same
// procedure linkage table for both programs and shared objects."
static const unsigned char first_plt_entry[plt_entry_size];
// Other entries in the PLT for an executable.
static const unsigned char plt_entry[plt_entry_size];
// The reserved TLSDESC entry in the PLT for an executable.
static const unsigned char tlsdesc_plt_entry[plt_entry_size];
// The .eh_frame unwind information for the PLT.
static const int plt_eh_frame_fde_size = 32;
static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
};
class Output_data_plt_x86_64_bnd : public Output_data_plt_x86_64<64>
{
public:
Output_data_plt_x86_64_bnd(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative)
: Output_data_plt_x86_64<64>(layout, plt_entry_size,
got, got_plt, got_irelative),
aplt_offset_(0)
{ }
Output_data_plt_x86_64_bnd(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative,
unsigned int plt_count)
: Output_data_plt_x86_64<64>(layout, plt_entry_size,
got, got_plt, got_irelative,
plt_count),
aplt_offset_(0)
{ }
protected:
virtual unsigned int
do_get_plt_entry_size() const
{ return plt_entry_size; }
// Return the PLT address to use for a global symbol.
uint64_t
do_address_for_global(const Symbol*);
// Return the PLT address to use for a local symbol.
uint64_t
do_address_for_local(const Relobj*, unsigned int symndx);
virtual void
do_add_eh_frame(Layout* layout)
{
layout->add_eh_frame_for_plt(this,
this->plt_eh_frame_cie,
this->plt_eh_frame_cie_size,
plt_eh_frame_fde,
plt_eh_frame_fde_size);
}
virtual void
do_fill_first_plt_entry(unsigned char* pov,
elfcpp::Elf_types<64>::Elf_Addr got_addr,
elfcpp::Elf_types<64>::Elf_Addr plt_addr);
virtual unsigned int
do_fill_plt_entry(unsigned char* pov,
elfcpp::Elf_types<64>::Elf_Addr got_address,
elfcpp::Elf_types<64>::Elf_Addr plt_address,
unsigned int got_offset,
unsigned int plt_offset,
unsigned int plt_index);
virtual void
do_fill_tlsdesc_entry(unsigned char* pov,
elfcpp::Elf_types<64>::Elf_Addr got_address,
elfcpp::Elf_types<64>::Elf_Addr plt_address,
elfcpp::Elf_types<64>::Elf_Addr got_base,
unsigned int tlsdesc_got_offset,
unsigned int plt_offset);
void
fill_aplt_entry(unsigned char* pov,
elfcpp::Elf_types<64>::Elf_Addr got_address,
elfcpp::Elf_types<64>::Elf_Addr plt_address,
unsigned int got_offset,
unsigned int plt_offset,
unsigned int plt_index);
private:
// Set the final size.
void
set_final_data_size();
// Write out the BND PLT data.
void
do_write(Output_file*);
// Offset of the Additional PLT (if using -z bndplt).
unsigned int aplt_offset_;
// The size of an entry in the PLT.
static const int plt_entry_size = 16;
// The size of an entry in the additional PLT.
static const int aplt_entry_size = 8;
// The first entry in the PLT.
// From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same
// procedure linkage table for both programs and shared objects."
static const unsigned char first_plt_entry[plt_entry_size];
// Other entries in the PLT for an executable.
static const unsigned char plt_entry[plt_entry_size];
// Entries in the additional PLT.
static const unsigned char aplt_entry[aplt_entry_size];
// The reserved TLSDESC entry in the PLT for an executable.
static const unsigned char tlsdesc_plt_entry[plt_entry_size];
// The .eh_frame unwind information for the PLT.
static const int plt_eh_frame_fde_size = 32;
static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
};
// We use this PLT when Indirect Branch Tracking (IBT) is enabled.
template <int size>
class Output_data_plt_x86_64_ibt : public Output_data_plt_x86_64<size>
{
public:
Output_data_plt_x86_64_ibt(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative)
: Output_data_plt_x86_64<size>(layout, plt_entry_size,
got, got_plt, got_irelative),
aplt_offset_(0)
{ }
Output_data_plt_x86_64_ibt(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative,
unsigned int plt_count)
: Output_data_plt_x86_64<size>(layout, plt_entry_size,
got, got_plt, got_irelative,
plt_count),
aplt_offset_(0)
{ }
protected:
virtual unsigned int
do_get_plt_entry_size() const
{ return plt_entry_size; }
// Return the PLT address to use for a global symbol.
uint64_t
do_address_for_global(const Symbol*);
// Return the PLT address to use for a local symbol.
uint64_t
do_address_for_local(const Relobj*, unsigned int symndx);
virtual void
do_add_eh_frame(Layout* layout)
{
layout->add_eh_frame_for_plt(this,
this->plt_eh_frame_cie,
this->plt_eh_frame_cie_size,
plt_eh_frame_fde,
plt_eh_frame_fde_size);
}
virtual void
do_fill_first_plt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
typename elfcpp::Elf_types<size>::Elf_Addr plt_addr);
virtual unsigned int
do_fill_plt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
unsigned int got_offset,
unsigned int plt_offset,
unsigned int plt_index);
virtual void
do_fill_tlsdesc_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
typename elfcpp::Elf_types<size>::Elf_Addr got_base,
unsigned int tlsdesc_got_offset,
unsigned int plt_offset);
void
fill_aplt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
unsigned int got_offset,
unsigned int plt_offset,
unsigned int plt_index);
private:
// Set the final size.
void
set_final_data_size();
// Write out the BND PLT data.
void
do_write(Output_file*);
// Offset of the Additional PLT (if using -z bndplt).
unsigned int aplt_offset_;
// The size of an entry in the PLT.
static const int plt_entry_size = 16;
// The size of an entry in the additional PLT.
static const int aplt_entry_size = 16;
// The first entry in the PLT.
// From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same
// procedure linkage table for both programs and shared objects."
static const unsigned char first_plt_entry[plt_entry_size];
// Other entries in the PLT for an executable.
static const unsigned char plt_entry[plt_entry_size];
// Entries in the additional PLT.
static const unsigned char aplt_entry[aplt_entry_size];
// The reserved TLSDESC entry in the PLT for an executable.
static const unsigned char tlsdesc_plt_entry[plt_entry_size];
// The .eh_frame unwind information for the PLT.
static const int plt_eh_frame_fde_size = 32;
static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
};
template<int size>
class Lazy_view
{
public:
Lazy_view(Sized_relobj_file<size, false>* object, unsigned int data_shndx)
: object_(object), data_shndx_(data_shndx), view_(NULL), view_size_(0)
{ }
inline unsigned char
operator[](size_t offset)
{
if (this->view_ == NULL)
this->view_ = this->object_->section_contents(this->data_shndx_,
&this->view_size_,
true);
if (offset >= this->view_size_)
return 0;
return this->view_[offset];
}
private:
Sized_relobj_file<size, false>* object_;
unsigned int data_shndx_;
const unsigned char* view_;
section_size_type view_size_;
};
// The x86_64 target class.
// See the ABI at
// http://www.x86-64.org/documentation/abi.pdf
// TLS info comes from
// http://people.redhat.com/drepper/tls.pdf
// http://www.lsd.ic.unicamp.br/~oliva/writeups/TLS/RFC-TLSDESC-x86.txt
template<int size>
class Target_x86_64 : public Sized_target<size, false>
{
public:
// In the x86_64 ABI (p 68), it says "The AMD64 ABI architectures
// uses only Elf64_Rela relocation entries with explicit addends."
typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, false> Reloc_section;
Target_x86_64(const Target::Target_info* info = &x86_64_info)
: Sized_target<size, false>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL),
rela_irelative_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY),
got_mod_index_offset_(-1U), tlsdesc_reloc_info_(),
tls_base_symbol_defined_(false), isa_1_used_(0), isa_1_needed_(0),
feature_1_(0), object_isa_1_used_(0), object_feature_1_(0),
seen_first_object_(false)
{ }
// Hook for a new output section.
void
do_new_output_section(Output_section*) const;
// Scan the relocations to look for symbol adjustments.
void
gc_process_relocs(Symbol_table* symtab,
Layout* layout,
Sized_relobj_file<size, false>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols);
// Scan the relocations to look for symbol adjustments.
void
scan_relocs(Symbol_table* symtab,
Layout* layout,
Sized_relobj_file<size, false>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols);
// Finalize the sections.
void
do_finalize_sections(Layout*, const Input_objects*, Symbol_table*);
// Return the value to use for a dynamic which requires special
// treatment.
uint64_t
do_dynsym_value(const Symbol*) const;
// Relocate a section.
void
relocate_section(const Relocate_info<size, false>*,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
section_size_type view_size,
const Reloc_symbol_changes*);
// Scan the relocs during a relocatable link.
void
scan_relocatable_relocs(Symbol_table* symtab,
Layout* layout,
Sized_relobj_file<size, false>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Relocatable_relocs*);
// Scan the relocs for --emit-relocs.
void
emit_relocs_scan(Symbol_table* symtab,
Layout* layout,
Sized_relobj_file<size, false>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_syms,
Relocatable_relocs* rr);
// Emit relocations for a section.
void
relocate_relocs(
const Relocate_info<size, false>*,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
section_size_type view_size,
unsigned char* reloc_view,
section_size_type reloc_view_size);
// Return a string used to fill a code section with nops.
std::string
do_code_fill(section_size_type length) const;
// Return whether SYM is defined by the ABI.
bool
do_is_defined_by_abi(const Symbol* sym) const
{ return strcmp(sym->name(), "__tls_get_addr") == 0; }
// Return the symbol index to use for a target specific relocation.
// The only target specific relocation is R_X86_64_TLSDESC for a
// local symbol, which is an absolute reloc.
unsigned int
do_reloc_symbol_index(void*, unsigned int r_type) const
{
gold_assert(r_type == elfcpp::R_X86_64_TLSDESC);
return 0;
}
// Return the addend to use for a target specific relocation.
uint64_t
do_reloc_addend(void* arg, unsigned int r_type, uint64_t addend) const;
// Return the PLT section.
uint64_t
do_plt_address_for_global(const Symbol* gsym) const
{ return this->plt_section()->address_for_global(gsym); }
uint64_t
do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const
{ return this->plt_section()->address_for_local(relobj, symndx); }
// This function should be defined in targets that can use relocation
// types to determine (implemented in local_reloc_may_be_function_pointer
// and global_reloc_may_be_function_pointer)
// if a function's pointer is taken. ICF uses this in safe mode to only
// fold those functions whose pointer is defintely not taken. For x86_64
// pie binaries, safe ICF cannot be done by looking at only relocation
// types, and for certain cases (e.g. R_X86_64_PC32), the instruction
// opcode is checked as well to distinguish a function call from taking
// a function's pointer.
bool
do_can_check_for_function_pointers() const
{ return true; }
// Return the base for a DW_EH_PE_datarel encoding.
uint64_t
do_ehframe_datarel_base() const;
// Adjust -fsplit-stack code which calls non-split-stack code.
void
do_calls_non_split(Relobj* object, unsigned int shndx,
section_offset_type fnoffset, section_size_type fnsize,
const unsigned char* prelocs, size_t reloc_count,
unsigned char* view, section_size_type view_size,
std::string* from, std::string* to) const;
// Return the size of the GOT section.
section_size_type
got_size() const
{
gold_assert(this->got_ != NULL);
return this->got_->data_size();
}
// Return the number of entries in the GOT.
unsigned int
got_entry_count() const
{
if (this->got_ == NULL)
return 0;
return this->got_size() / 8;
}
// Return the number of entries in the PLT.
unsigned int
plt_entry_count() const;
// Return the offset of the first non-reserved PLT entry.
unsigned int
first_plt_entry_offset() const;
// Return the size of each PLT entry.
unsigned int
plt_entry_size() const;
// Return the size of each GOT entry.
unsigned int
got_entry_size() const
{ return 8; };
// Create the GOT section for an incremental update.
Output_data_got_base*
init_got_plt_for_update(Symbol_table* symtab,
Layout* layout,
unsigned int got_count,
unsigned int plt_count);
// Reserve a GOT entry for a local symbol, and regenerate any
// necessary dynamic relocations.
void
reserve_local_got_entry(unsigned int got_index,
Sized_relobj<size, false>* obj,
unsigned int r_sym,
unsigned int got_type);
// Reserve a GOT entry for a global symbol, and regenerate any
// necessary dynamic relocations.
void
reserve_global_got_entry(unsigned int got_index, Symbol* gsym,
unsigned int got_type);
// Register an existing PLT entry for a global symbol.
void
register_global_plt_entry(Symbol_table*, Layout*, unsigned int plt_index,
Symbol* gsym);
// Force a COPY relocation for a given symbol.
void
emit_copy_reloc(Symbol_table*, Symbol*, Output_section*, off_t);
// Apply an incremental relocation.
void
apply_relocation(const Relocate_info<size, false>* relinfo,
typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
unsigned int r_type,
typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
const Symbol* gsym,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr address,
section_size_type view_size);
// Add a new reloc argument, returning the index in the vector.
size_t
add_tlsdesc_info(Sized_relobj_file<size, false>* object, unsigned int r_sym)
{
this->tlsdesc_reloc_info_.push_back(Tlsdesc_info(object, r_sym));
return this->tlsdesc_reloc_info_.size() - 1;
}
Output_data_plt_x86_64<size>*
make_data_plt(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative)
{
return this->do_make_data_plt(layout, got, got_plt, got_irelative);
}
Output_data_plt_x86_64<size>*
make_data_plt(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative,
unsigned int plt_count)
{
return this->do_make_data_plt(layout, got, got_plt, got_irelative,
plt_count);
}
virtual Output_data_plt_x86_64<size>*
do_make_data_plt(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative);
virtual Output_data_plt_x86_64<size>*
do_make_data_plt(Layout* layout,
Output_data_got<64, false>* got,
Output_data_got_plt_x86_64* got_plt,
Output_data_space* got_irelative,
unsigned int plt_count);
private:
// The class which scans relocations.
class Scan
{
public:
Scan()
: issued_non_pic_error_(false)
{ }
static inline int
get_reference_flags(unsigned int r_type);
inline void
local(Symbol_table* symtab, Layout* layout, Target_x86_64* target,
Sized_relobj_file<size, false>* object,
unsigned int data_shndx,