Commit | Line | Data |
---|---|---|
61ba1cf9 ILT |
1 | // target-reloc.h -- target specific relocation support -*- C++ -*- |
2 | ||
3 | #ifndef GOLD_TARGET_RELOC_H | |
4 | #define GOLD_TARGET_RELOC_H | |
5 | ||
6 | #include "elfcpp.h" | |
7 | #include "symtab.h" | |
8 | ||
9 | namespace gold | |
10 | { | |
11 | ||
12 | // Pick the ELF relocation accessor class and the size based on | |
13 | // SH_TYPE, which is either SHT_REL or SHT_RELA. | |
14 | ||
15 | template<int sh_type, int size, bool big_endian> | |
16 | struct Reloc_types; | |
17 | ||
18 | template<int size, bool big_endian> | |
19 | struct Reloc_types<elfcpp::SHT_REL, size, big_endian> | |
20 | { | |
21 | typedef typename elfcpp::Rel<size, big_endian> Reloc; | |
22 | static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size; | |
23 | }; | |
24 | ||
25 | template<int size, bool big_endian> | |
26 | struct Reloc_types<elfcpp::SHT_RELA, size, big_endian> | |
27 | { | |
28 | typedef typename elfcpp::Rela<size, big_endian> Reloc; | |
29 | static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size; | |
30 | }; | |
31 | ||
32 | // This function implements the generic part of relocation handling. | |
33 | // This is an inline function which take a class whose operator() | |
34 | // implements the machine specific part of relocation. We do it this | |
35 | // way to avoid making a function call for each relocation, and to | |
36 | // avoid repeating the generic relocation handling code for each | |
37 | // target. | |
38 | ||
39 | // SIZE is the ELF size: 32 or 64. BIG_ENDIAN is the endianness of | |
40 | // the data. SH_TYPE is the section type: SHT_REL or SHT_RELA. RELOC | |
41 | // implements operator() to do a relocation. | |
42 | ||
43 | // OBJECT is the object for we are processing relocs. SH_TYPE is the | |
44 | // type of relocation: SHT_REL or SHT_RELA. PRELOCS points to the | |
45 | // relocation data. RELOC_COUNT is the number of relocs. LOCAL_COUNT | |
46 | // is the number of local symbols. LOCAL_VALUES holds the values of | |
47 | // the local symbols. GLOBAL_SYMS points to the global symbols. VIEW | |
48 | // is the section data, VIEW_ADDRESS is its memory address, and | |
49 | // VIEW_SIZE is the size. | |
50 | ||
51 | template<int size, bool big_endian, int sh_type, typename Relocate> | |
52 | inline void | |
53 | relocate_section( | |
54 | const Symbol_table* symtab, | |
55 | Sized_object<size, big_endian>* object, | |
56 | const unsigned char* prelocs, | |
57 | size_t reloc_count, | |
58 | size_t local_count, | |
59 | const typename elfcpp::Elf_types<size>::Elf_Addr* local_values, | |
60 | Symbol** global_syms, | |
61 | unsigned char* view, | |
62 | typename elfcpp::Elf_types<size>::Elf_Addr view_address, | |
63 | off_t view_size) | |
64 | { | |
65 | typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype; | |
66 | const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size; | |
67 | Relocate relocate; | |
68 | ||
69 | for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size) | |
70 | { | |
71 | Reltype reloc(prelocs); | |
72 | ||
73 | off_t offset = reloc.get_r_offset(); | |
74 | if (offset < 0 || offset >= view_size) | |
75 | { | |
76 | fprintf(stderr, _("%s: %s: reloc %zu has bad offset %lu\n"), | |
77 | program_name, object->name().c_str(), i, | |
78 | static_cast<unsigned long>(offset)); | |
79 | gold_exit(false); | |
80 | } | |
81 | ||
82 | typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info(); | |
83 | unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info); | |
84 | unsigned int r_type = elfcpp::elf_r_type<size>(r_info); | |
85 | ||
86 | Sized_symbol<size>* sym; | |
87 | typename elfcpp::Elf_types<size>::Elf_Addr value; | |
88 | ||
89 | if (r_sym < local_count) | |
90 | { | |
91 | sym = NULL; | |
92 | value = local_values[r_sym]; | |
93 | } | |
94 | else | |
95 | { | |
96 | Symbol* gsym = global_syms[r_sym - local_count]; | |
a783673b | 97 | assert(gsym != NULL); |
61ba1cf9 ILT |
98 | if (gsym->is_forwarder()) |
99 | gsym = symtab->resolve_forwards(gsym); | |
100 | ||
101 | sym = static_cast<Sized_symbol<size>*>(gsym); | |
102 | value = sym->value(); | |
103 | ||
104 | if (sym->shnum() == elfcpp::SHN_UNDEF | |
105 | && sym->binding() != elfcpp::STB_WEAK) | |
106 | { | |
107 | fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"), | |
108 | program_name, object->name().c_str(), sym->name()); | |
109 | // gold_exit(false); | |
110 | } | |
111 | } | |
112 | ||
113 | relocate(object, reloc, r_type, sym, value, view + offset, | |
114 | view_address + offset); | |
115 | } | |
116 | } | |
117 | ||
118 | } // End namespace gold. | |
119 | ||
120 | #endif // !defined(GOLD_TARGET_RELOC_H) |