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