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