Hash tables, dynamic section, i386 PLT, gold_assert.
[external/binutils.git] / gold / target-reloc.h
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 "object.h"
8 #include "symtab.h"
9 #include "reloc-types.h"
10
11 namespace gold
12 {
13
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
20 template<int size, bool big_endian, typename Target_type, int sh_type,
21          typename Scan>
22 inline void
23 scan_relocs(
24     const General_options& options,
25     Symbol_table* symtab,
26     Layout* layout,
27     Target_type* target,
28     Sized_relobj<size, big_endian>* object,
29     unsigned int data_shndx,
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         {
51           gold_assert(plocal_syms != NULL);
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
56               && shndx != elfcpp::SHN_UNDEF
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
77           scan.local(options, symtab, layout, target, object, data_shndx,
78                      reloc, r_type, lsym);
79         }
80       else
81         {
82           Symbol* gsym = global_syms[r_sym - local_count];
83           gold_assert(gsym != NULL);
84           if (gsym->is_forwarder())
85             gsym = symtab->resolve_forwards(gsym);
86
87           scan.global(options, symtab, layout, target, object, data_shndx,
88                       reloc, r_type, gsym);
89         }
90     }
91 }
92
93 // This function implements the generic part of relocation processing.
94 // This is an inline function which take a class whose operator()
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
101 // the data.  SH_TYPE is the section type: SHT_REL or SHT_RELA.
102 // RELOCATE implements operator() to do a relocation.
103
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.
107
108 template<int size, bool big_endian, typename Target_type, int sh_type,
109          typename Relocate>
110 inline void
111 relocate_section(
112     const Relocate_info<size, big_endian>* relinfo,
113     Target_type* target,
114     const unsigned char* prelocs,
115     size_t reloc_count,
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
124   unsigned int local_count = relinfo->local_symbol_count;
125   const typename Sized_relobj<size, big_endian>::Local_values* local_values =
126     relinfo->local_values;
127   const Symbol* const * global_syms = relinfo->symbols;
128
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();
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
139       const Sized_symbol<size>* sym;
140       typename elfcpp::Elf_types<size>::Elf_Addr value;
141
142       if (r_sym < local_count)
143         {
144           sym = NULL;
145           value = (*local_values)[r_sym];
146         }
147       else
148         {
149           const Symbol* gsym = global_syms[r_sym - local_count];
150           gold_assert(gsym != NULL);
151           if (gsym->is_forwarder())
152             gsym = relinfo->symtab->resolve_forwards(gsym);
153
154           sym = static_cast<const Sized_symbol<size>*>(gsym);
155           value = sym->value();
156         }
157
158       if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, value,
159                              view + offset, view_address + offset, view_size))
160         continue;
161
162       if (offset < 0 || offset >= view_size)
163         {
164           fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"),
165                   program_name, relinfo->location(i, offset).c_str(),
166                   static_cast<size_t>(offset));
167           gold_exit(false);
168         }
169
170       if (sym != NULL
171           && sym->is_undefined()
172           && sym->binding() != elfcpp::STB_WEAK)
173         {
174           fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
175                   program_name, relinfo->location(i, offset).c_str(),
176                   sym->name());
177           // gold_exit(false);
178         }
179
180       if (sym != NULL && sym->has_warning())
181         relinfo->symtab->issue_warning(sym, relinfo->location(i, offset));
182     }
183 }
184
185 } // End namespace gold.
186
187 #endif // !defined(GOLD_TARGET_RELOC_H)