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