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" | |
92e059d8 | 7 | #include "object.h" |
61ba1cf9 ILT |
8 | #include "symtab.h" |
9 | ||
10 | namespace gold | |
11 | { | |
12 | ||
13 | // Pick the ELF relocation accessor class and the size based on | |
14 | // SH_TYPE, which is either SHT_REL or SHT_RELA. | |
15 | ||
16 | template<int sh_type, int size, bool big_endian> | |
17 | struct Reloc_types; | |
18 | ||
19 | template<int size, bool big_endian> | |
20 | struct Reloc_types<elfcpp::SHT_REL, size, big_endian> | |
21 | { | |
22 | typedef typename elfcpp::Rel<size, big_endian> Reloc; | |
23 | static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size; | |
24 | }; | |
25 | ||
26 | template<int size, bool big_endian> | |
27 | struct Reloc_types<elfcpp::SHT_RELA, size, big_endian> | |
28 | { | |
29 | typedef typename elfcpp::Rela<size, big_endian> Reloc; | |
30 | static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size; | |
31 | }; | |
32 | ||
92e059d8 ILT |
33 | // This function implements the generic part of reloc scanning. This |
34 | // is an inline function which takes a class whose operator() | |
35 | // implements the machine specific part of scanning. We do it this | |
36 | // way to avoidmaking a function call for each relocation, and to | |
37 | // avoid repeating the generic code for each target. | |
38 | ||
39 | template<int size, bool big_endian, int sh_type, typename Scan> | |
40 | inline void | |
41 | scan_relocs( | |
42 | const General_options& options, | |
43 | Symbol_table* symtab, | |
44 | Sized_object<size, big_endian>* object, | |
45 | const unsigned char* prelocs, | |
46 | size_t reloc_count, | |
47 | size_t local_count, | |
48 | const unsigned char* plocal_syms, | |
49 | Symbol** global_syms) | |
50 | { | |
51 | typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype; | |
52 | const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size; | |
53 | const int sym_size = elfcpp::Elf_sizes<size>::sym_size; | |
54 | Scan scan; | |
55 | ||
56 | for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size) | |
57 | { | |
58 | Reltype reloc(prelocs); | |
59 | ||
60 | typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info(); | |
61 | unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info); | |
62 | unsigned int r_type = elfcpp::elf_r_type<size>(r_info); | |
63 | ||
64 | if (r_sym < local_count) | |
65 | { | |
66 | assert(plocal_syms != NULL); | |
67 | typename elfcpp::Sym<size, big_endian> lsym(plocal_syms | |
68 | + r_sym * sym_size); | |
69 | const unsigned int shndx = lsym.get_st_shndx(); | |
70 | if (shndx < elfcpp::SHN_LORESERVE | |
71 | && !object->is_section_included(lsym.get_st_shndx())) | |
72 | { | |
73 | // RELOC is a relocation against a local symbol in a | |
74 | // section we are discarding. We can ignore this | |
75 | // relocation. It will eventually become a reloc | |
76 | // against the value zero. | |
77 | // | |
78 | // FIXME: We should issue a warning if this is an | |
79 | // allocated section; is this the best place to do it? | |
80 | // | |
81 | // FIXME: The old GNU linker would in some cases look | |
82 | // for the linkonce section which caused this section to | |
83 | // be discarded, and, if the other section was the same | |
84 | // size, change the reloc to refer to the other section. | |
85 | // That seems risky and weird to me, and I don't know of | |
86 | // any case where it is actually required. | |
87 | ||
88 | continue; | |
89 | } | |
90 | ||
91 | scan.local(options, object, reloc, r_type, lsym); | |
92 | } | |
93 | else | |
94 | { | |
95 | Symbol* gsym = global_syms[r_sym - local_count]; | |
96 | assert(gsym != NULL); | |
97 | if (gsym->is_forwarder()) | |
98 | gsym = symtab->resolve_forwards(gsym); | |
99 | ||
100 | scan.global(options, object, reloc, r_type, gsym); | |
101 | } | |
102 | } | |
103 | } | |
104 | ||
105 | // This function implements the generic part of relocation processing. | |
61ba1cf9 ILT |
106 | // This is an inline function which take a class whose operator() |
107 | // implements the machine specific part of relocation. We do it this | |
108 | // way to avoid making a function call for each relocation, and to | |
109 | // avoid repeating the generic relocation handling code for each | |
110 | // target. | |
111 | ||
112 | // SIZE is the ELF size: 32 or 64. BIG_ENDIAN is the endianness of | |
92e059d8 ILT |
113 | // the data. SH_TYPE is the section type: SHT_REL or SHT_RELA. |
114 | // RELOCATE implements operator() to do a relocation. | |
61ba1cf9 | 115 | |
92e059d8 ILT |
116 | // PRELOCS points to the relocation data. RELOC_COUNT is the number |
117 | // of relocs. VIEW is the section data, VIEW_ADDRESS is its memory | |
118 | // address, and VIEW_SIZE is the size. | |
61ba1cf9 ILT |
119 | |
120 | template<int size, bool big_endian, int sh_type, typename Relocate> | |
121 | inline void | |
122 | relocate_section( | |
92e059d8 | 123 | const Relocate_info<size, big_endian>* relinfo, |
61ba1cf9 ILT |
124 | const unsigned char* prelocs, |
125 | size_t reloc_count, | |
61ba1cf9 ILT |
126 | unsigned char* view, |
127 | typename elfcpp::Elf_types<size>::Elf_Addr view_address, | |
128 | off_t view_size) | |
129 | { | |
130 | typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype; | |
131 | const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size; | |
132 | Relocate relocate; | |
133 | ||
92e059d8 ILT |
134 | unsigned int local_count = relinfo->local_symbol_count; |
135 | typename elfcpp::Elf_types<size>::Elf_Addr *local_values = relinfo->values; | |
136 | Symbol** global_syms = relinfo->symbols; | |
137 | ||
61ba1cf9 ILT |
138 | for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size) |
139 | { | |
140 | Reltype reloc(prelocs); | |
141 | ||
142 | off_t offset = reloc.get_r_offset(); | |
143 | if (offset < 0 || offset >= view_size) | |
144 | { | |
92e059d8 ILT |
145 | fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"), |
146 | program_name, relinfo->location(i, offset).c_str(), | |
147 | static_cast<size_t>(offset)); | |
61ba1cf9 ILT |
148 | gold_exit(false); |
149 | } | |
150 | ||
151 | typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info(); | |
152 | unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info); | |
153 | unsigned int r_type = elfcpp::elf_r_type<size>(r_info); | |
154 | ||
155 | Sized_symbol<size>* sym; | |
156 | typename elfcpp::Elf_types<size>::Elf_Addr value; | |
157 | ||
158 | if (r_sym < local_count) | |
159 | { | |
160 | sym = NULL; | |
161 | value = local_values[r_sym]; | |
162 | } | |
163 | else | |
164 | { | |
165 | Symbol* gsym = global_syms[r_sym - local_count]; | |
a783673b | 166 | assert(gsym != NULL); |
61ba1cf9 | 167 | if (gsym->is_forwarder()) |
92e059d8 | 168 | gsym = relinfo->symtab->resolve_forwards(gsym); |
61ba1cf9 ILT |
169 | |
170 | sym = static_cast<Sized_symbol<size>*>(gsym); | |
171 | value = sym->value(); | |
172 | ||
173 | if (sym->shnum() == elfcpp::SHN_UNDEF | |
174 | && sym->binding() != elfcpp::STB_WEAK) | |
175 | { | |
176 | fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"), | |
92e059d8 ILT |
177 | program_name, relinfo->location(i, offset).c_str(), |
178 | sym->name()); | |
61ba1cf9 ILT |
179 | // gold_exit(false); |
180 | } | |
181 | } | |
182 | ||
92e059d8 ILT |
183 | relocate.relocate(relinfo, i, reloc, r_type, sym, value, view + offset, |
184 | view_address + offset, view_size); | |
61ba1cf9 ILT |
185 | } |
186 | } | |
187 | ||
188 | } // End namespace gold. | |
189 | ||
190 | #endif // !defined(GOLD_TARGET_RELOC_H) |