From Andrew Chatham: exit on relocation error.
[external/binutils.git] / gold / target-reloc.h
1 // target-reloc.h -- target specific relocation support  -*- C++ -*-
2
3 // Copyright 2006, 2007 Free Software Foundation, Inc.
4 // Written by Ian Lance Taylor <iant@google.com>.
5
6 // This file is part of gold.
7
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 3 of the License, or
11 // (at your option) any later version.
12
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 // MA 02110-1301, USA.
22
23 #ifndef GOLD_TARGET_RELOC_H
24 #define GOLD_TARGET_RELOC_H
25
26 #include "elfcpp.h"
27 #include "object.h"
28 #include "symtab.h"
29 #include "reloc-types.h"
30
31 namespace gold
32 {
33
34 // This function implements the generic part of reloc scanning.  This
35 // is an inline function which takes a class whose operator()
36 // implements the machine specific part of scanning.  We do it this
37 // way to avoidmaking a function call for each relocation, and to
38 // avoid repeating the generic code for each target.
39
40 template<int size, bool big_endian, typename Target_type, int sh_type,
41          typename Scan>
42 inline void
43 scan_relocs(
44     const General_options& options,
45     Symbol_table* symtab,
46     Layout* layout,
47     Target_type* target,
48     Sized_relobj<size, big_endian>* object,
49     unsigned int data_shndx,
50     const unsigned char* prelocs,
51     size_t reloc_count,
52     size_t local_count,
53     const unsigned char* plocal_syms,
54     Symbol** global_syms)
55 {
56   typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
57   const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
58   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
59   Scan scan;
60
61   for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
62     {
63       Reltype reloc(prelocs);
64
65       typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
66       unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
67       unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
68
69       if (r_sym < local_count)
70         {
71           gold_assert(plocal_syms != NULL);
72           typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
73                                                       + r_sym * sym_size);
74           const unsigned int shndx = lsym.get_st_shndx();
75           if (shndx < elfcpp::SHN_LORESERVE
76               && shndx != elfcpp::SHN_UNDEF
77               && !object->is_section_included(lsym.get_st_shndx()))
78             {
79               // RELOC is a relocation against a local symbol in a
80               // section we are discarding.  We can ignore this
81               // relocation.  It will eventually become a reloc
82               // against the value zero.
83               //
84               // FIXME: We should issue a warning if this is an
85               // allocated section; is this the best place to do it?
86               // 
87               // FIXME: The old GNU linker would in some cases look
88               // for the linkonce section which caused this section to
89               // be discarded, and, if the other section was the same
90               // size, change the reloc to refer to the other section.
91               // That seems risky and weird to me, and I don't know of
92               // any case where it is actually required.
93
94               continue;
95             }
96
97           scan.local(options, symtab, layout, target, object, data_shndx,
98                      reloc, r_type, lsym);
99         }
100       else
101         {
102           Symbol* gsym = global_syms[r_sym - local_count];
103           gold_assert(gsym != NULL);
104           if (gsym->is_forwarder())
105             gsym = symtab->resolve_forwards(gsym);
106
107           scan.global(options, symtab, layout, target, object, data_shndx,
108                       reloc, r_type, gsym);
109         }
110     }
111 }
112
113 // This function implements the generic part of relocation processing.
114 // This is an inline function which take a class whose relocate()
115 // implements the machine specific part of relocation.  We do it this
116 // way to avoid making a function call for each relocation, and to
117 // avoid repeating the generic relocation handling code for each
118 // target.
119
120 // SIZE is the ELF size: 32 or 64.  BIG_ENDIAN is the endianness of
121 // the data.  SH_TYPE is the section type: SHT_REL or SHT_RELA.
122 // RELOCATE implements operator() to do a relocation.
123
124 // PRELOCS points to the relocation data.  RELOC_COUNT is the number
125 // of relocs.  VIEW is the section data, VIEW_ADDRESS is its memory
126 // address, and VIEW_SIZE is the size.
127
128 template<int size, bool big_endian, typename Target_type, int sh_type,
129          typename Relocate>
130 inline void
131 relocate_section(
132     const Relocate_info<size, big_endian>* relinfo,
133     Target_type* target,
134     const unsigned char* prelocs,
135     size_t reloc_count,
136     unsigned char* view,
137     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
138     off_t view_size)
139 {
140   typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
141   const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
142   Relocate relocate;
143
144   unsigned int local_count = relinfo->local_symbol_count;
145   const typename Sized_relobj<size, big_endian>::Local_values* local_values =
146     relinfo->local_values;
147   const Symbol* const * global_syms = relinfo->symbols;
148
149   for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
150     {
151       Reltype reloc(prelocs);
152
153       off_t offset = reloc.get_r_offset();
154
155       typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
156       unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
157       unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
158
159       const Sized_symbol<size>* sym;
160
161       Symbol_value<size> symval;
162       const Symbol_value<size> *psymval;
163       if (r_sym < local_count)
164         {
165           sym = NULL;
166           psymval = &(*local_values)[r_sym];
167         }
168       else
169         {
170           const Symbol* gsym = global_syms[r_sym - local_count];
171           gold_assert(gsym != NULL);
172           if (gsym->is_forwarder())
173             gsym = relinfo->symtab->resolve_forwards(gsym);
174
175           sym = static_cast<const Sized_symbol<size>*>(gsym);
176           if (sym->has_symtab_index())
177             symval.set_output_symtab_index(sym->symtab_index());
178           else
179             symval.set_no_output_symtab_entry();
180           symval.set_output_value(sym->value());
181           psymval = &symval;
182         }
183
184       if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, psymval,
185                              view + offset, view_address + offset, view_size))
186         continue;
187
188       if (offset < 0 || offset >= view_size)
189         {
190           fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"),
191                   program_name, relinfo->location(i, offset).c_str(),
192                   static_cast<size_t>(offset));
193           gold_exit(false);
194         }
195
196       if (sym != NULL
197           && sym->is_undefined()
198           && sym->binding() != elfcpp::STB_WEAK)
199         {
200           fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
201                   program_name, relinfo->location(i, offset).c_str(),
202                   sym->name());
203           gold_exit(false);
204         }
205
206       if (sym != NULL && sym->has_warning())
207         relinfo->symtab->issue_warning(sym, relinfo->location(i, offset));
208     }
209 }
210
211 } // End namespace gold.
212
213 #endif // !defined(GOLD_TARGET_RELOC_H)