Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 1 | // copy-relocs.cc -- handle COPY relocations for gold. |
| 2 | |
Alan Modra | a2c5833 | 2022-01-02 09:00:17 +1030 | [diff] [blame] | 3 | // Copyright (C) 2006-2022 Free Software Foundation, Inc. |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 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 | #include "gold.h" |
| 24 | |
| 25 | #include "symtab.h" |
| 26 | #include "copy-relocs.h" |
| 27 | |
| 28 | namespace gold |
| 29 | { |
| 30 | |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 31 | // Copy_relocs methods. |
| 32 | |
| 33 | // Handle a relocation against a symbol which may force us to generate |
| 34 | // a COPY reloc. |
| 35 | |
| 36 | template<int sh_type, int size, bool big_endian> |
| 37 | void |
| 38 | Copy_relocs<sh_type, size, big_endian>::copy_reloc( |
| 39 | Symbol_table* symtab, |
| 40 | Layout* layout, |
| 41 | Sized_symbol<size>* sym, |
Cary Coutant | 6fa2a40 | 2011-05-24 21:41:10 +0000 | [diff] [blame] | 42 | Sized_relobj_file<size, big_endian>* object, |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 43 | unsigned int shndx, |
Nick Clifton | ca09d69 | 2010-08-25 08:36:54 +0000 | [diff] [blame] | 44 | Output_section* output_section, |
Cary Coutant | 859d798 | 2015-11-09 08:43:46 -0800 | [diff] [blame] | 45 | unsigned int r_type, |
| 46 | typename elfcpp::Elf_types<size>::Elf_Addr r_offset, |
| 47 | typename elfcpp::Elf_types<size>::Elf_Swxword r_addend, |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 48 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) |
| 49 | { |
| 50 | if (this->need_copy_reloc(sym, object, shndx)) |
Cary Coutant | 6eeb017 | 2016-05-19 14:58:18 -0700 | [diff] [blame] | 51 | this->make_copy_reloc(symtab, layout, sym, object, reloc_section); |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 52 | else |
| 53 | { |
| 54 | // We may not need a COPY relocation. Save this relocation to |
| 55 | // possibly be emitted later. |
Cary Coutant | 859d798 | 2015-11-09 08:43:46 -0800 | [diff] [blame] | 56 | this->save(sym, object, shndx, output_section, |
| 57 | r_type, r_offset, r_addend); |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 58 | } |
| 59 | } |
| 60 | |
| 61 | // Return whether we need a COPY reloc for a relocation against SYM. |
| 62 | // The relocation is begin applied to section SHNDX in OBJECT. |
| 63 | |
| 64 | template<int sh_type, int size, bool big_endian> |
| 65 | bool |
| 66 | Copy_relocs<sh_type, size, big_endian>::need_copy_reloc( |
| 67 | Sized_symbol<size>* sym, |
Cary Coutant | 6fa2a40 | 2011-05-24 21:41:10 +0000 | [diff] [blame] | 68 | Sized_relobj_file<size, big_endian>* object, |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 69 | unsigned int shndx) const |
| 70 | { |
Doug Kwan | 966d409 | 2009-10-01 00:58:38 +0000 | [diff] [blame] | 71 | if (!parameters->options().copyreloc()) |
| 72 | return false; |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 73 | |
| 74 | if (sym->symsize() == 0) |
| 75 | return false; |
| 76 | |
| 77 | // If this is a readonly section, then we need a COPY reloc. |
| 78 | // Otherwise we can use a dynamic reloc. Note that calling |
| 79 | // section_flags here can be slow, as the information is not cached; |
| 80 | // fortunately we shouldn't see too many potential COPY relocs. |
| 81 | if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0) |
| 82 | return true; |
| 83 | |
| 84 | return false; |
| 85 | } |
| 86 | |
| 87 | // Emit a COPY relocation for SYM. |
| 88 | |
| 89 | template<int sh_type, int size, bool big_endian> |
| 90 | void |
| 91 | Copy_relocs<sh_type, size, big_endian>::emit_copy_reloc( |
| 92 | Symbol_table* symtab, |
Cary Coutant | 26d3c67 | 2011-06-08 03:50:12 +0000 | [diff] [blame] | 93 | Sized_symbol<size>* sym, |
| 94 | Output_data* posd, |
| 95 | off_t offset, |
| 96 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) |
| 97 | { |
| 98 | // Define the symbol as being copied. |
| 99 | symtab->define_with_copy_reloc(sym, posd, offset); |
| 100 | |
| 101 | // Add the COPY relocation to the dynamic reloc section. |
Ian Lance Taylor | 8389620 | 2011-12-19 21:07:16 +0000 | [diff] [blame] | 102 | reloc_section->add_global_generic(sym, this->copy_reloc_type_, posd, |
| 103 | offset, 0); |
Cary Coutant | 26d3c67 | 2011-06-08 03:50:12 +0000 | [diff] [blame] | 104 | } |
| 105 | |
| 106 | // Make a COPY relocation for SYM and emit it. |
| 107 | |
| 108 | template<int sh_type, int size, bool big_endian> |
| 109 | void |
| 110 | Copy_relocs<sh_type, size, big_endian>::make_copy_reloc( |
| 111 | Symbol_table* symtab, |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 112 | Layout* layout, |
| 113 | Sized_symbol<size>* sym, |
Cary Coutant | 6eeb017 | 2016-05-19 14:58:18 -0700 | [diff] [blame] | 114 | Sized_relobj_file<size, big_endian>* object, |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 115 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) |
| 116 | { |
Doug Kwan | 966d409 | 2009-10-01 00:58:38 +0000 | [diff] [blame] | 117 | // We should not be here if -z nocopyreloc is given. |
| 118 | gold_assert(parameters->options().copyreloc()); |
| 119 | |
Cary Coutant | 6eeb017 | 2016-05-19 14:58:18 -0700 | [diff] [blame] | 120 | gold_assert(sym->is_from_dynobj()); |
| 121 | |
| 122 | // The symbol must not have protected visibility. |
| 123 | if (sym->is_protected()) |
| 124 | { |
| 125 | gold_error(_("%s: cannot make copy relocation for " |
| 126 | "protected symbol '%s', defined in %s"), |
| 127 | object->name().c_str(), |
| 128 | sym->name(), |
| 129 | sym->object()->name().c_str()); |
| 130 | } |
| 131 | |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 132 | typename elfcpp::Elf_types<size>::Elf_WXword symsize = sym->symsize(); |
| 133 | |
| 134 | // There is no defined way to determine the required alignment of |
| 135 | // the symbol. We know that the symbol is defined in a dynamic |
| 136 | // object. We start with the alignment of the section in which it |
| 137 | // is defined; presumably we do not require an alignment larger than |
| 138 | // that. Then we reduce that alignment if the symbol is not aligned |
| 139 | // within the section. |
Ian Lance Taylor | d491d34 | 2008-04-19 18:30:58 +0000 | [diff] [blame] | 140 | bool is_ordinary; |
| 141 | unsigned int shndx = sym->shndx(&is_ordinary); |
| 142 | gold_assert(is_ordinary); |
Cary Coutant | 5f9bcf5 | 2010-11-05 21:14:33 +0000 | [diff] [blame] | 143 | typename elfcpp::Elf_types<size>::Elf_WXword addralign; |
Cary Coutant | b733bcb | 2016-12-27 20:50:47 -0800 | [diff] [blame] | 144 | bool is_readonly = false; |
Cary Coutant | 5f9bcf5 | 2010-11-05 21:14:33 +0000 | [diff] [blame] | 145 | |
| 146 | { |
| 147 | // Lock the object so we can read from it. This is only called |
| 148 | // single-threaded from scan_relocs, so it is OK to lock. |
| 149 | // Unfortunately we have no way to pass in a Task token. |
| 150 | const Task* dummy_task = reinterpret_cast<const Task*>(-1); |
| 151 | Object* obj = sym->object(); |
| 152 | Task_lock_obj<Object> tl(dummy_task, obj); |
| 153 | addralign = obj->section_addralign(shndx); |
Cary Coutant | b733bcb | 2016-12-27 20:50:47 -0800 | [diff] [blame] | 154 | if (parameters->options().relro()) |
| 155 | { |
| 156 | if ((obj->section_flags(shndx) & elfcpp::SHF_WRITE) == 0) |
| 157 | is_readonly = true; |
| 158 | else |
| 159 | { |
| 160 | // Symbols in .data.rel.ro should also be treated as read-only. |
| 161 | if (obj->section_name(shndx) == ".data.rel.ro") |
| 162 | is_readonly = true; |
| 163 | } |
| 164 | } |
Cary Coutant | 5f9bcf5 | 2010-11-05 21:14:33 +0000 | [diff] [blame] | 165 | } |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 166 | |
| 167 | typename Sized_symbol<size>::Value_type value = sym->value(); |
| 168 | while ((value & (addralign - 1)) != 0) |
| 169 | addralign >>= 1; |
| 170 | |
Ian Lance Taylor | 659948a | 2010-01-07 19:32:59 +0000 | [diff] [blame] | 171 | // Mark the dynamic object as needed for the --as-needed option. |
| 172 | sym->object()->set_is_needed(); |
| 173 | |
Cary Coutant | b733bcb | 2016-12-27 20:50:47 -0800 | [diff] [blame] | 174 | Output_data_space* dynbss; |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 175 | |
Cary Coutant | b733bcb | 2016-12-27 20:50:47 -0800 | [diff] [blame] | 176 | if (is_readonly) |
| 177 | { |
| 178 | if (this->dynrelro_ == NULL) |
| 179 | { |
| 180 | this->dynrelro_ = new Output_data_space(addralign, "** dynrelro"); |
| 181 | layout->add_output_section_data(".data.rel.ro", |
| 182 | elfcpp::SHT_PROGBITS, |
| 183 | elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, |
| 184 | this->dynrelro_, ORDER_RELRO, false); |
| 185 | } |
| 186 | dynbss = this->dynrelro_; |
| 187 | } |
| 188 | else |
| 189 | { |
| 190 | if (this->dynbss_ == NULL) |
| 191 | { |
| 192 | this->dynbss_ = new Output_data_space(addralign, "** dynbss"); |
| 193 | layout->add_output_section_data(".bss", |
| 194 | elfcpp::SHT_NOBITS, |
| 195 | elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, |
| 196 | this->dynbss_, ORDER_BSS, false); |
| 197 | } |
| 198 | dynbss = this->dynbss_; |
| 199 | } |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 200 | |
| 201 | if (addralign > dynbss->addralign()) |
| 202 | dynbss->set_space_alignment(addralign); |
| 203 | |
| 204 | section_size_type dynbss_size = |
| 205 | convert_to_section_size_type(dynbss->current_data_size()); |
| 206 | dynbss_size = align_address(dynbss_size, addralign); |
| 207 | section_size_type offset = dynbss_size; |
| 208 | dynbss->set_current_data_size(dynbss_size + symsize); |
| 209 | |
Cary Coutant | 26d3c67 | 2011-06-08 03:50:12 +0000 | [diff] [blame] | 210 | this->emit_copy_reloc(symtab, sym, dynbss, offset, reloc_section); |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | // Save a relocation to possibly be emitted later. |
| 214 | |
| 215 | template<int sh_type, int size, bool big_endian> |
| 216 | void |
Ian Lance Taylor | ef9bedd | 2008-07-10 23:01:20 +0000 | [diff] [blame] | 217 | Copy_relocs<sh_type, size, big_endian>::save( |
| 218 | Symbol* sym, |
Cary Coutant | 6fa2a40 | 2011-05-24 21:41:10 +0000 | [diff] [blame] | 219 | Sized_relobj_file<size, big_endian>* object, |
Ian Lance Taylor | ef9bedd | 2008-07-10 23:01:20 +0000 | [diff] [blame] | 220 | unsigned int shndx, |
| 221 | Output_section* output_section, |
Cary Coutant | 859d798 | 2015-11-09 08:43:46 -0800 | [diff] [blame] | 222 | unsigned int r_type, |
| 223 | typename elfcpp::Elf_types<size>::Elf_Addr r_offset, |
| 224 | typename elfcpp::Elf_types<size>::Elf_Swxword r_addend) |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 225 | { |
Cary Coutant | 859d798 | 2015-11-09 08:43:46 -0800 | [diff] [blame] | 226 | this->entries_.push_back(Copy_reloc_entry(sym, r_type, object, shndx, |
| 227 | output_section, r_offset, |
| 228 | r_addend)); |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 229 | } |
| 230 | |
| 231 | // Emit any saved relocs. |
| 232 | |
| 233 | template<int sh_type, int size, bool big_endian> |
| 234 | void |
| 235 | Copy_relocs<sh_type, size, big_endian>::emit( |
| 236 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_section) |
| 237 | { |
| 238 | for (typename Copy_reloc_entries::iterator p = this->entries_.begin(); |
| 239 | p != this->entries_.end(); |
| 240 | ++p) |
Cary Coutant | 91f43ac | 2014-04-15 11:19:18 -0700 | [diff] [blame] | 241 | { |
| 242 | Copy_reloc_entry& entry = *p; |
| 243 | |
| 244 | // If the symbol is no longer defined in a dynamic object, then we |
| 245 | // emitted a COPY relocation, and we do not want to emit this |
| 246 | // dynamic relocation. |
| 247 | if (entry.sym_->is_from_dynobj()) |
| 248 | reloc_section->add_global_generic(entry.sym_, entry.reloc_type_, |
| 249 | entry.output_section_, entry.relobj_, |
| 250 | entry.shndx_, entry.address_, |
| 251 | entry.addend_); |
| 252 | } |
Ian Lance Taylor | 12c0dae | 2008-04-16 22:54:29 +0000 | [diff] [blame] | 253 | |
| 254 | // We no longer need the saved information. |
| 255 | this->entries_.clear(); |
| 256 | } |
| 257 | |
| 258 | // Instantiate the templates we need. |
| 259 | |
| 260 | #ifdef HAVE_TARGET_32_LITTLE |
| 261 | template |
| 262 | class Copy_relocs<elfcpp::SHT_REL, 32, false>; |
| 263 | |
| 264 | template |
| 265 | class Copy_relocs<elfcpp::SHT_RELA, 32, false>; |
| 266 | #endif |
| 267 | |
| 268 | #ifdef HAVE_TARGET_32_BIG |
| 269 | template |
| 270 | class Copy_relocs<elfcpp::SHT_REL, 32, true>; |
| 271 | |
| 272 | template |
| 273 | class Copy_relocs<elfcpp::SHT_RELA, 32, true>; |
| 274 | #endif |
| 275 | |
| 276 | #ifdef HAVE_TARGET_64_LITTLE |
| 277 | template |
| 278 | class Copy_relocs<elfcpp::SHT_REL, 64, false>; |
| 279 | |
| 280 | template |
| 281 | class Copy_relocs<elfcpp::SHT_RELA, 64, false>; |
| 282 | #endif |
| 283 | |
| 284 | #ifdef HAVE_TARGET_64_BIG |
| 285 | template |
| 286 | class Copy_relocs<elfcpp::SHT_REL, 64, true>; |
| 287 | |
| 288 | template |
| 289 | class Copy_relocs<elfcpp::SHT_RELA, 64, true>; |
| 290 | #endif |
| 291 | |
| 292 | } // End namespace gold. |