diff options
| author | Khem Raj <raj.khem@gmail.com> | 2016-01-14 03:58:10 -0800 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-01-24 09:40:31 +0000 |
| commit | 136db70700ce198f793935d0683ce4e1f1acf471 (patch) | |
| tree | 4d197ae3c35c91a8dee182f21158873abd6e1fa5 | |
| parent | 704e34213ed2925ab3ac135717861c4ff466e8ab (diff) | |
| download | poky-136db70700ce198f793935d0683ce4e1f1acf471.tar.gz | |
binutils: Fix gold linking errors due to unresolved R_ARM_MOVW_ABS_NC
This issue has been seen in multiple times e.g.
http://patchwork.openembedded.org/patch/103083/
https://www.mail-archive.com/openembedded-core@lists.openembedded.org/msg72513.html
(From OE-Core rev: 9db094039ed7bce34006cc21bb65cd800fbfee7d)
Signed-off-by: Khem Raj <raj.khem@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
| -rw-r--r-- | meta/recipes-devtools/binutils/binutils-2.25.1.inc | 1 | ||||
| -rw-r--r-- | meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch | 1004 |
2 files changed, 1005 insertions, 0 deletions
diff --git a/meta/recipes-devtools/binutils/binutils-2.25.1.inc b/meta/recipes-devtools/binutils/binutils-2.25.1.inc index bf29da16f5..dc23c4d9d9 100644 --- a/meta/recipes-devtools/binutils/binutils-2.25.1.inc +++ b/meta/recipes-devtools/binutils/binutils-2.25.1.inc | |||
| @@ -35,6 +35,7 @@ SRC_URI = "\ | |||
| 35 | file://0013-Fix-an-internal-error-in-do_print_to_mapfile-seen-wi.patch \ | 35 | file://0013-Fix-an-internal-error-in-do_print_to_mapfile-seen-wi.patch \ |
| 36 | file://0014-gold-arm-Skip-pic-check-for-R_ARM_REL32.patch \ | 36 | file://0014-gold-arm-Skip-pic-check-for-R_ARM_REL32.patch \ |
| 37 | file://0015-Fix-dynamic-list-so-that-symbols-not-in-the-list-are.patch \ | 37 | file://0015-Fix-dynamic-list-so-that-symbols-not-in-the-list-are.patch \ |
| 38 | file://0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch \ | ||
| 38 | file://binutils-octeon3.patch \ | 39 | file://binutils-octeon3.patch \ |
| 39 | file://add-thunderx-support-for-gas.patch \ | 40 | file://add-thunderx-support-for-gas.patch \ |
| 40 | " | 41 | " |
diff --git a/meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch b/meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch new file mode 100644 index 0000000000..dcac308bcc --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0016-This-patch-adds-IFUNC-support-for-arm-gold-backend.patch | |||
| @@ -0,0 +1,1004 @@ | |||
| 1 | From b780c9e06cabe6d8e301aaf46f33f116f3224021 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Han Shen <shenhan@google.com> | ||
| 3 | Date: Thu, 29 Jan 2015 10:00:46 -0800 | ||
| 4 | Subject: [PATCH] This patch adds IFUNC support for arm gold backend. | ||
| 5 | |||
| 6 | This is a feature required in chromeos arm development work. | ||
| 7 | |||
| 8 | Tested: | ||
| 9 | 1) Built passed all-gold on x86_64 machine | ||
| 10 | 2) Tested with basic gold aarch64 ifunc unittests - | ||
| 11 | a) global ifunc, statically/non-statically linked | ||
| 12 | b) local ifunc, statically/non-statically linked | ||
| 13 | c) global/local, other shared library routine mixed, | ||
| 14 | statically/non-statically linked | ||
| 15 | d) arm/thumb mode ifunc | ||
| 16 | e) linking chrome browser passed | ||
| 17 | --- | ||
| 18 | Upstream-Status: Backport | ||
| 19 | Signed-off-by: Khem Raj <raj.khem@gmail.com> | ||
| 20 | |||
| 21 | elfcpp/arm.h | 5 +- | ||
| 22 | gold/aarch64.cc | 2 +- | ||
| 23 | gold/arm.cc | 593 +++++++++++++++++++++++++++++++++++++++++++++++++++----- | ||
| 24 | gold/output.h | 11 ++ | ||
| 25 | 4 files changed, 561 insertions(+), 50 deletions(-) | ||
| 26 | |||
| 27 | diff --git a/elfcpp/arm.h b/elfcpp/arm.h | ||
| 28 | index 8c6b6bf..1c13dc9 100644 | ||
| 29 | --- a/elfcpp/arm.h | ||
| 30 | +++ b/elfcpp/arm.h | ||
| 31 | @@ -192,11 +192,12 @@ enum | ||
| 32 | R_ARM_PRIVATE_14 = 126, | ||
| 33 | R_ARM_PRIVATE_15 = 127, | ||
| 34 | R_ARM_ME_TOO = 128, // Obsolete | ||
| 35 | - R_ARM_THM_TLS_DESCSEQ16 = 129,// Static Thumb16 | ||
| 36 | + R_ARM_THM_TLS_DESCSEQ16 = 129,// Static Thumb16 | ||
| 37 | R_ARM_THM_TLS_DESCSEQ32 = 130,// Static Thumb32 | ||
| 38 | // 131 - 139 Unallocated | ||
| 39 | // 140 - 159 Dynamic Reserved for future allocation | ||
| 40 | - // 160 - 255 Unallocated | ||
| 41 | + R_ARM_IRELATIVE = 160, // Dynamic | ||
| 42 | + // 161 - 255 Unallocated | ||
| 43 | }; | ||
| 44 | |||
| 45 | // e_flags values used for ARM. We only support flags defined in AAELF. | ||
| 46 | diff --git a/gold/aarch64.cc b/gold/aarch64.cc | ||
| 47 | index afb9024..7fbbdbd 100644 | ||
| 48 | --- a/gold/aarch64.cc | ||
| 49 | +++ b/gold/aarch64.cc | ||
| 50 | @@ -1226,7 +1226,7 @@ class Output_data_plt_aarch64 : public Output_section_data | ||
| 51 | // The number of PLT entries. | ||
| 52 | unsigned int count_; | ||
| 53 | |||
| 54 | - // Number of PLT entries with R_X86_64_IRELATIVE relocs. These | ||
| 55 | + // Number of PLT entries with R_AARCH64_IRELATIVE relocs. These | ||
| 56 | // follow the regular PLT entries. | ||
| 57 | unsigned int irelative_count_; | ||
| 58 | |||
| 59 | diff --git a/gold/arm.cc b/gold/arm.cc | ||
| 60 | index 6c472bb..8719cc9 100644 | ||
| 61 | --- a/gold/arm.cc | ||
| 62 | +++ b/gold/arm.cc | ||
| 63 | @@ -2119,8 +2119,8 @@ class Target_arm : public Sized_target<32, big_endian> | ||
| 64 | |||
| 65 | Target_arm(const Target::Target_info* info = &arm_info) | ||
| 66 | : Sized_target<32, big_endian>(info), | ||
| 67 | - got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL), | ||
| 68 | - copy_relocs_(elfcpp::R_ARM_COPY), | ||
| 69 | + got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL), | ||
| 70 | + rel_dyn_(NULL), rel_irelative_(NULL), copy_relocs_(elfcpp::R_ARM_COPY), | ||
| 71 | got_mod_index_offset_(-1U), tls_base_symbol_defined_(false), | ||
| 72 | stub_tables_(), stub_factory_(Stub_factory::get_instance()), | ||
| 73 | should_force_pic_veneer_(false), | ||
| 74 | @@ -2258,6 +2258,18 @@ class Target_arm : public Sized_target<32, big_endian> | ||
| 75 | uint64_t | ||
| 76 | do_dynsym_value(const Symbol*) const; | ||
| 77 | |||
| 78 | + // Return the plt address for globals. Since we have irelative plt entries, | ||
| 79 | + // address calculation is not as straightforward as plt_address + plt_offset. | ||
| 80 | + uint64_t | ||
| 81 | + do_plt_address_for_global(const Symbol* gsym) const | ||
| 82 | + { return this->plt_section()->address_for_global(gsym); } | ||
| 83 | + | ||
| 84 | + // Return the plt address for locals. Since we have irelative plt entries, | ||
| 85 | + // address calculation is not as straightforward as plt_address + plt_offset. | ||
| 86 | + uint64_t | ||
| 87 | + do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const | ||
| 88 | + { return this->plt_section()->address_for_local(relobj, symndx); } | ||
| 89 | + | ||
| 90 | // Relocate a section. | ||
| 91 | void | ||
| 92 | relocate_section(const Relocate_info<32, big_endian>*, | ||
| 93 | @@ -2357,6 +2369,10 @@ class Target_arm : public Sized_target<32, big_endian> | ||
| 94 | unsigned int | ||
| 95 | plt_entry_size() const; | ||
| 96 | |||
| 97 | + // Get the section to use for IRELATIVE relocations, create it if necessary. | ||
| 98 | + Reloc_section* | ||
| 99 | + rel_irelative_section(Layout*); | ||
| 100 | + | ||
| 101 | // Map platform-specific reloc types | ||
| 102 | static unsigned int | ||
| 103 | get_real_reloc_type(unsigned int r_type); | ||
| 104 | @@ -2448,8 +2464,11 @@ class Target_arm : public Sized_target<32, big_endian> | ||
| 105 | protected: | ||
| 106 | // Make the PLT-generator object. | ||
| 107 | Output_data_plt_arm<big_endian>* | ||
| 108 | - make_data_plt(Layout* layout, Output_data_space* got_plt) | ||
| 109 | - { return this->do_make_data_plt(layout, got_plt); } | ||
| 110 | + make_data_plt(Layout* layout, | ||
| 111 | + Arm_output_data_got<big_endian>* got, | ||
| 112 | + Output_data_space* got_plt, | ||
| 113 | + Output_data_space* got_irelative) | ||
| 114 | + { return this->do_make_data_plt(layout, got, got_plt, got_irelative); } | ||
| 115 | |||
| 116 | // Make an ELF object. | ||
| 117 | Object* | ||
| 118 | @@ -2530,9 +2549,14 @@ class Target_arm : public Sized_target<32, big_endian> | ||
| 119 | do_define_standard_symbols(Symbol_table*, Layout*); | ||
| 120 | |||
| 121 | virtual Output_data_plt_arm<big_endian>* | ||
| 122 | - do_make_data_plt(Layout* layout, Output_data_space* got_plt) | ||
| 123 | + do_make_data_plt(Layout* layout, | ||
| 124 | + Arm_output_data_got<big_endian>* got, | ||
| 125 | + Output_data_space* got_plt, | ||
| 126 | + Output_data_space* got_irelative) | ||
| 127 | { | ||
| 128 | - return new Output_data_plt_arm_standard<big_endian>(layout, got_plt); | ||
| 129 | + gold_assert(got_plt != NULL && got_irelative != NULL); | ||
| 130 | + return new Output_data_plt_arm_standard<big_endian>( | ||
| 131 | + layout, got, got_plt, got_irelative); | ||
| 132 | } | ||
| 133 | |||
| 134 | private: | ||
| 135 | @@ -2602,6 +2626,9 @@ class Target_arm : public Sized_target<32, big_endian> | ||
| 136 | if (sym->is_undefined() && !parameters->options().shared()) | ||
| 137 | return false; | ||
| 138 | |||
| 139 | + if (sym->type() == elfcpp::STT_GNU_IFUNC) | ||
| 140 | + return true; | ||
| 141 | + | ||
| 142 | return (!parameters->doing_static_link() | ||
| 143 | && (sym->type() == elfcpp::STT_FUNC | ||
| 144 | || sym->type() == elfcpp::STT_ARM_TFUNC) | ||
| 145 | @@ -2613,6 +2640,11 @@ class Target_arm : public Sized_target<32, big_endian> | ||
| 146 | inline bool | ||
| 147 | possible_function_pointer_reloc(unsigned int r_type); | ||
| 148 | |||
| 149 | + // Whether a plt entry is needed for ifunc. | ||
| 150 | + bool | ||
| 151 | + reloc_needs_plt_for_ifunc(Sized_relobj_file<32, big_endian>*, | ||
| 152 | + unsigned int r_type); | ||
| 153 | + | ||
| 154 | // Whether we have issued an error about a non-PIC compilation. | ||
| 155 | bool issued_non_pic_error_; | ||
| 156 | }; | ||
| 157 | @@ -2718,10 +2750,20 @@ class Target_arm : public Sized_target<32, big_endian> | ||
| 158 | return this->got_plt_; | ||
| 159 | } | ||
| 160 | |||
| 161 | + // Create the PLT section. | ||
| 162 | + void | ||
| 163 | + make_plt_section(Symbol_table* symtab, Layout* layout); | ||
| 164 | + | ||
| 165 | // Create a PLT entry for a global symbol. | ||
| 166 | void | ||
| 167 | make_plt_entry(Symbol_table*, Layout*, Symbol*); | ||
| 168 | |||
| 169 | + // Create a PLT entry for a local STT_GNU_IFUNC symbol. | ||
| 170 | + void | ||
| 171 | + make_local_ifunc_plt_entry(Symbol_table*, Layout*, | ||
| 172 | + Sized_relobj_file<32, big_endian>* relobj, | ||
| 173 | + unsigned int local_sym_index); | ||
| 174 | + | ||
| 175 | // Define the _TLS_MODULE_BASE_ symbol in the TLS segment. | ||
| 176 | void | ||
| 177 | define_tls_base_symbol(Symbol_table*, Layout*); | ||
| 178 | @@ -2903,8 +2945,12 @@ class Target_arm : public Sized_target<32, big_endian> | ||
| 179 | Output_data_plt_arm<big_endian>* plt_; | ||
| 180 | // The GOT PLT section. | ||
| 181 | Output_data_space* got_plt_; | ||
| 182 | + // The GOT section for IRELATIVE relocations. | ||
| 183 | + Output_data_space* got_irelative_; | ||
| 184 | // The dynamic reloc section. | ||
| 185 | Reloc_section* rel_dyn_; | ||
| 186 | + // The section to use for IRELATIVE relocs. | ||
| 187 | + Reloc_section* rel_irelative_; | ||
| 188 | // Relocs saved to avoid a COPY reloc. | ||
| 189 | Copy_relocs<elfcpp::SHT_REL, 32, big_endian> copy_relocs_; | ||
| 190 | // Offset of the GOT entry for the TLS module index. | ||
| 191 | @@ -4244,6 +4290,15 @@ Target_arm<big_endian>::got_section(Symbol_table* symtab, Layout* layout) | ||
| 192 | elfcpp::STB_LOCAL, | ||
| 193 | elfcpp::STV_HIDDEN, 0, | ||
| 194 | false, false); | ||
| 195 | + | ||
| 196 | + // If there are any IRELATIVE relocations, they get GOT entries | ||
| 197 | + // in .got.plt after the jump slot entries. | ||
| 198 | + this->got_irelative_ = new Output_data_space(4, "** GOT IRELATIVE PLT"); | ||
| 199 | + layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, | ||
| 200 | + (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), | ||
| 201 | + this->got_irelative_, | ||
| 202 | + got_order, is_got_relro); | ||
| 203 | + | ||
| 204 | } | ||
| 205 | return this->got_; | ||
| 206 | } | ||
| 207 | @@ -4257,14 +4312,43 @@ Target_arm<big_endian>::rel_dyn_section(Layout* layout) | ||
| 208 | if (this->rel_dyn_ == NULL) | ||
| 209 | { | ||
| 210 | gold_assert(layout != NULL); | ||
| 211 | + // Create both relocation sections in the same place, so as to ensure | ||
| 212 | + // their relative order in the output section. | ||
| 213 | this->rel_dyn_ = new Reloc_section(parameters->options().combreloc()); | ||
| 214 | + this->rel_irelative_ = new Reloc_section(false); | ||
| 215 | layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, | ||
| 216 | elfcpp::SHF_ALLOC, this->rel_dyn_, | ||
| 217 | ORDER_DYNAMIC_RELOCS, false); | ||
| 218 | + layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, | ||
| 219 | + elfcpp::SHF_ALLOC, this->rel_irelative_, | ||
| 220 | + ORDER_DYNAMIC_RELOCS, false); | ||
| 221 | } | ||
| 222 | return this->rel_dyn_; | ||
| 223 | } | ||
| 224 | |||
| 225 | + | ||
| 226 | +// Get the section to use for IRELATIVE relocs, creating it if necessary. These | ||
| 227 | +// go in .rela.dyn, but only after all other dynamic relocations. They need to | ||
| 228 | +// follow the other dynamic relocations so that they can refer to global | ||
| 229 | +// variables initialized by those relocs. | ||
| 230 | + | ||
| 231 | +template<bool big_endian> | ||
| 232 | +typename Target_arm<big_endian>::Reloc_section* | ||
| 233 | +Target_arm<big_endian>::rel_irelative_section(Layout* layout) | ||
| 234 | +{ | ||
| 235 | + if (this->rel_irelative_ == NULL) | ||
| 236 | + { | ||
| 237 | + // Delegate the creation to rel_dyn_section so as to ensure their order in | ||
| 238 | + // the output section. | ||
| 239 | + this->rel_dyn_section(layout); | ||
| 240 | + gold_assert(this->rel_irelative_ != NULL | ||
| 241 | + && (this->rel_dyn_->output_section() | ||
| 242 | + == this->rel_irelative_->output_section())); | ||
| 243 | + } | ||
| 244 | + return this->rel_irelative_; | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | + | ||
| 248 | // Insn_template methods. | ||
| 249 | |||
| 250 | // Return byte size of an instruction template. | ||
| 251 | @@ -7221,24 +7305,80 @@ template<bool big_endian> | ||
| 252 | class Output_data_plt_arm : public Output_section_data | ||
| 253 | { | ||
| 254 | public: | ||
| 255 | + // Unlike aarch64, which records symbol value in "addend" field of relocations | ||
| 256 | + // and could be done at the same time an IRelative reloc is created for the | ||
| 257 | + // symbol, arm puts the symbol value into "GOT" table, which, however, is | ||
| 258 | + // issued later in Output_data_plt_arm::do_write(). So we have a struct here | ||
| 259 | + // to keep necessary symbol information for later use in do_write. We usually | ||
| 260 | + // have only a very limited number of ifuncs, so the extra data required here | ||
| 261 | + // is also limited. | ||
| 262 | + | ||
| 263 | + struct IRelative_data | ||
| 264 | + { | ||
| 265 | + IRelative_data(Sized_symbol<32>* sized_symbol) | ||
| 266 | + : symbol_is_global_(true) | ||
| 267 | + { | ||
| 268 | + u_.global = sized_symbol; | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + IRelative_data(Sized_relobj_file<32, big_endian>* relobj, | ||
| 272 | + unsigned int index) | ||
| 273 | + : symbol_is_global_(false) | ||
| 274 | + { | ||
| 275 | + u_.local.relobj = relobj; | ||
| 276 | + u_.local.index = index; | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + union | ||
| 280 | + { | ||
| 281 | + Sized_symbol<32>* global; | ||
| 282 | + | ||
| 283 | + struct | ||
| 284 | + { | ||
| 285 | + Sized_relobj_file<32, big_endian>* relobj; | ||
| 286 | + unsigned int index; | ||
| 287 | + } local; | ||
| 288 | + } u_; | ||
| 289 | + | ||
| 290 | + bool symbol_is_global_; | ||
| 291 | + }; | ||
| 292 | + | ||
| 293 | typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian> | ||
| 294 | Reloc_section; | ||
| 295 | |||
| 296 | - Output_data_plt_arm(Layout*, uint64_t addralign, Output_data_space*); | ||
| 297 | + Output_data_plt_arm(Layout* layout, uint64_t addralign, | ||
| 298 | + Arm_output_data_got<big_endian>* got, | ||
| 299 | + Output_data_space* got_plt, | ||
| 300 | + Output_data_space* got_irelative); | ||
| 301 | |||
| 302 | // Add an entry to the PLT. | ||
| 303 | void | ||
| 304 | - add_entry(Symbol* gsym); | ||
| 305 | + add_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym); | ||
| 306 | + | ||
| 307 | + // Add the relocation for a plt entry. | ||
| 308 | + void | ||
| 309 | + add_relocation(Symbol_table* symtab, Layout* layout, | ||
| 310 | + Symbol* gsym, unsigned int got_offset); | ||
| 311 | + | ||
| 312 | + // Add an entry to the PLT for a local STT_GNU_IFUNC symbol. | ||
| 313 | + unsigned int | ||
| 314 | + add_local_ifunc_entry(Symbol_table* symtab, Layout*, | ||
| 315 | + Sized_relobj_file<32, big_endian>* relobj, | ||
| 316 | + unsigned int local_sym_index); | ||
| 317 | |||
| 318 | // Return the .rel.plt section data. | ||
| 319 | const Reloc_section* | ||
| 320 | rel_plt() const | ||
| 321 | { return this->rel_; } | ||
| 322 | |||
| 323 | + // Return the PLT relocation container for IRELATIVE. | ||
| 324 | + Reloc_section* | ||
| 325 | + rel_irelative(Symbol_table*, Layout*); | ||
| 326 | + | ||
| 327 | // Return the number of PLT entries. | ||
| 328 | unsigned int | ||
| 329 | entry_count() const | ||
| 330 | - { return this->count_; } | ||
| 331 | + { return this->count_ + this->irelative_count_; } | ||
| 332 | |||
| 333 | // Return the offset of the first non-reserved PLT entry. | ||
| 334 | unsigned int | ||
| 335 | @@ -7250,6 +7390,14 @@ class Output_data_plt_arm : public Output_section_data | ||
| 336 | get_plt_entry_size() const | ||
| 337 | { return this->do_get_plt_entry_size(); } | ||
| 338 | |||
| 339 | + // Return the PLT address for globals. | ||
| 340 | + uint32_t | ||
| 341 | + address_for_global(const Symbol*) const; | ||
| 342 | + | ||
| 343 | + // Return the PLT address for locals. | ||
| 344 | + uint32_t | ||
| 345 | + address_for_local(const Relobj*, unsigned int symndx) const; | ||
| 346 | + | ||
| 347 | protected: | ||
| 348 | // Fill in the first PLT entry. | ||
| 349 | void | ||
| 350 | @@ -7298,19 +7446,37 @@ class Output_data_plt_arm : public Output_section_data | ||
| 351 | set_final_data_size() | ||
| 352 | { | ||
| 353 | this->set_data_size(this->first_plt_entry_offset() | ||
| 354 | - + this->count_ * this->get_plt_entry_size()); | ||
| 355 | + + ((this->count_ + this->irelative_count_) | ||
| 356 | + * this->get_plt_entry_size())); | ||
| 357 | } | ||
| 358 | |||
| 359 | // Write out the PLT data. | ||
| 360 | void | ||
| 361 | do_write(Output_file*); | ||
| 362 | |||
| 363 | + // Record irelative symbol data. | ||
| 364 | + void insert_irelative_data(const IRelative_data& idata) | ||
| 365 | + { irelative_data_vec_.push_back(idata); } | ||
| 366 | + | ||
| 367 | // The reloc section. | ||
| 368 | Reloc_section* rel_; | ||
| 369 | + // The IRELATIVE relocs, if necessary. These must follow the | ||
| 370 | + // regular PLT relocations. | ||
| 371 | + Reloc_section* irelative_rel_; | ||
| 372 | + // The .got section. | ||
| 373 | + Arm_output_data_got<big_endian>* got_; | ||
| 374 | // The .got.plt section. | ||
| 375 | Output_data_space* got_plt_; | ||
| 376 | + // The part of the .got.plt section used for IRELATIVE relocs. | ||
| 377 | + Output_data_space* got_irelative_; | ||
| 378 | // The number of PLT entries. | ||
| 379 | unsigned int count_; | ||
| 380 | + // Number of PLT entries with R_ARM_IRELATIVE relocs. These | ||
| 381 | + // follow the regular PLT entries. | ||
| 382 | + unsigned int irelative_count_; | ||
| 383 | + // Vector for irelative data. | ||
| 384 | + typedef std::vector<IRelative_data> IRelative_data_vec; | ||
| 385 | + IRelative_data_vec irelative_data_vec_; | ||
| 386 | }; | ||
| 387 | |||
| 388 | // Create the PLT section. The ordinary .got section is an argument, | ||
| 389 | @@ -7318,10 +7484,14 @@ class Output_data_plt_arm : public Output_section_data | ||
| 390 | // section just for PLT entries. | ||
| 391 | |||
| 392 | template<bool big_endian> | ||
| 393 | -Output_data_plt_arm<big_endian>::Output_data_plt_arm(Layout* layout, | ||
| 394 | - uint64_t addralign, | ||
| 395 | - Output_data_space* got_plt) | ||
| 396 | - : Output_section_data(addralign), got_plt_(got_plt), count_(0) | ||
| 397 | +Output_data_plt_arm<big_endian>::Output_data_plt_arm( | ||
| 398 | + Layout* layout, uint64_t addralign, | ||
| 399 | + Arm_output_data_got<big_endian>* got, | ||
| 400 | + Output_data_space* got_plt, | ||
| 401 | + Output_data_space* got_irelative) | ||
| 402 | + : Output_section_data(addralign), irelative_rel_(NULL), | ||
| 403 | + got_(got), got_plt_(got_plt), got_irelative_(got_irelative), | ||
| 404 | + count_(0), irelative_count_(0) | ||
| 405 | { | ||
| 406 | this->rel_ = new Reloc_section(false); | ||
| 407 | layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, | ||
| 408 | @@ -7340,40 +7510,210 @@ Output_data_plt_arm<big_endian>::do_adjust_output_section(Output_section* os) | ||
| 409 | |||
| 410 | template<bool big_endian> | ||
| 411 | void | ||
| 412 | -Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym) | ||
| 413 | +Output_data_plt_arm<big_endian>::add_entry(Symbol_table* symtab, | ||
| 414 | + Layout* layout, | ||
| 415 | + Symbol* gsym) | ||
| 416 | { | ||
| 417 | gold_assert(!gsym->has_plt_offset()); | ||
| 418 | |||
| 419 | - // Note that when setting the PLT offset we skip the initial | ||
| 420 | - // reserved PLT entry. | ||
| 421 | - gsym->set_plt_offset((this->count_) * this->get_plt_entry_size() | ||
| 422 | - + this->first_plt_entry_offset()); | ||
| 423 | + unsigned int* entry_count; | ||
| 424 | + Output_section_data_build* got; | ||
| 425 | + | ||
| 426 | + // We have 2 different types of plt entry here, normal and ifunc. | ||
| 427 | + | ||
| 428 | + // For normal plt, the offset begins with first_plt_entry_offset(20), and the | ||
| 429 | + // 1st entry offset would be 20, the second 32, third 44 ... etc. | ||
| 430 | + | ||
| 431 | + // For ifunc plt, the offset begins with 0. So the first offset would 0, | ||
| 432 | + // second 12, third 24 ... etc. | ||
| 433 | + | ||
| 434 | + // IFunc plt entries *always* come after *normal* plt entries. | ||
| 435 | + | ||
| 436 | + // Notice, when computing the plt address of a certain symbol, "plt_address + | ||
| 437 | + // plt_offset" is no longer correct. Use target->plt_address_for_global() or | ||
| 438 | + // target->plt_address_for_local() instead. | ||
| 439 | + | ||
| 440 | + int begin_offset = 0; | ||
| 441 | + if (gsym->type() == elfcpp::STT_GNU_IFUNC | ||
| 442 | + && gsym->can_use_relative_reloc(false)) | ||
| 443 | + { | ||
| 444 | + entry_count = &this->irelative_count_; | ||
| 445 | + got = this->got_irelative_; | ||
| 446 | + // For irelative plt entries, offset is relative to the end of normal plt | ||
| 447 | + // entries, so it starts from 0. | ||
| 448 | + begin_offset = 0; | ||
| 449 | + // Record symbol information. | ||
| 450 | + this->insert_irelative_data( | ||
| 451 | + IRelative_data(symtab->get_sized_symbol<32>(gsym))); | ||
| 452 | + } | ||
| 453 | + else | ||
| 454 | + { | ||
| 455 | + entry_count = &this->count_; | ||
| 456 | + got = this->got_plt_; | ||
| 457 | + // Note that for normal plt entries, when setting the PLT offset we skip | ||
| 458 | + // the initial reserved PLT entry. | ||
| 459 | + begin_offset = this->first_plt_entry_offset(); | ||
| 460 | + } | ||
| 461 | + | ||
| 462 | + gsym->set_plt_offset(begin_offset | ||
| 463 | + + (*entry_count) * this->get_plt_entry_size()); | ||
| 464 | |||
| 465 | - ++this->count_; | ||
| 466 | + ++(*entry_count); | ||
| 467 | |||
| 468 | - section_offset_type got_offset = this->got_plt_->current_data_size(); | ||
| 469 | + section_offset_type got_offset = got->current_data_size(); | ||
| 470 | |||
| 471 | // Every PLT entry needs a GOT entry which points back to the PLT | ||
| 472 | // entry (this will be changed by the dynamic linker, normally | ||
| 473 | // lazily when the function is called). | ||
| 474 | - this->got_plt_->set_current_data_size(got_offset + 4); | ||
| 475 | + got->set_current_data_size(got_offset + 4); | ||
| 476 | |||
| 477 | // Every PLT entry needs a reloc. | ||
| 478 | - gsym->set_needs_dynsym_entry(); | ||
| 479 | - this->rel_->add_global(gsym, elfcpp::R_ARM_JUMP_SLOT, this->got_plt_, | ||
| 480 | - got_offset); | ||
| 481 | + this->add_relocation(symtab, layout, gsym, got_offset); | ||
| 482 | |||
| 483 | // Note that we don't need to save the symbol. The contents of the | ||
| 484 | // PLT are independent of which symbols are used. The symbols only | ||
| 485 | // appear in the relocations. | ||
| 486 | } | ||
| 487 | |||
| 488 | +// Add an entry to the PLT for a local STT_GNU_IFUNC symbol. Return | ||
| 489 | +// the PLT offset. | ||
| 490 | + | ||
| 491 | +template<bool big_endian> | ||
| 492 | +unsigned int | ||
| 493 | +Output_data_plt_arm<big_endian>::add_local_ifunc_entry( | ||
| 494 | + Symbol_table* symtab, | ||
| 495 | + Layout* layout, | ||
| 496 | + Sized_relobj_file<32, big_endian>* relobj, | ||
| 497 | + unsigned int local_sym_index) | ||
| 498 | +{ | ||
| 499 | + this->insert_irelative_data(IRelative_data(relobj, local_sym_index)); | ||
| 500 | + | ||
| 501 | + // Notice, when computingthe plt entry address, "plt_address + plt_offset" is | ||
| 502 | + // no longer correct. Use target->plt_address_for_local() instead. | ||
| 503 | + unsigned int plt_offset = this->irelative_count_ * this->get_plt_entry_size(); | ||
| 504 | + ++this->irelative_count_; | ||
| 505 | + | ||
| 506 | + section_offset_type got_offset = this->got_irelative_->current_data_size(); | ||
| 507 | + | ||
| 508 | + // Every PLT entry needs a GOT entry which points back to the PLT | ||
| 509 | + // entry. | ||
| 510 | + this->got_irelative_->set_current_data_size(got_offset + 4); | ||
| 511 | + | ||
| 512 | + | ||
| 513 | + // Every PLT entry needs a reloc. | ||
| 514 | + Reloc_section* rel = this->rel_irelative(symtab, layout); | ||
| 515 | + rel->add_symbolless_local_addend(relobj, local_sym_index, | ||
| 516 | + elfcpp::R_ARM_IRELATIVE, | ||
| 517 | + this->got_irelative_, got_offset); | ||
| 518 | + return plt_offset; | ||
| 519 | +} | ||
| 520 | + | ||
| 521 | + | ||
| 522 | +// Add the relocation for a PLT entry. | ||
| 523 | + | ||
| 524 | +template<bool big_endian> | ||
| 525 | +void | ||
| 526 | +Output_data_plt_arm<big_endian>::add_relocation( | ||
| 527 | + Symbol_table* symtab, Layout* layout, Symbol* gsym, unsigned int got_offset) | ||
| 528 | +{ | ||
| 529 | + if (gsym->type() == elfcpp::STT_GNU_IFUNC | ||
| 530 | + && gsym->can_use_relative_reloc(false)) | ||
| 531 | + { | ||
| 532 | + Reloc_section* rel = this->rel_irelative(symtab, layout); | ||
| 533 | + rel->add_symbolless_global_addend(gsym, elfcpp::R_ARM_IRELATIVE, | ||
| 534 | + this->got_irelative_, got_offset); | ||
| 535 | + } | ||
| 536 | + else | ||
| 537 | + { | ||
| 538 | + gsym->set_needs_dynsym_entry(); | ||
| 539 | + this->rel_->add_global(gsym, elfcpp::R_ARM_JUMP_SLOT, this->got_plt_, | ||
| 540 | + got_offset); | ||
| 541 | + } | ||
| 542 | +} | ||
| 543 | + | ||
| 544 | + | ||
| 545 | +// Create the irelative relocation data. | ||
| 546 | + | ||
| 547 | +template<bool big_endian> | ||
| 548 | +typename Output_data_plt_arm<big_endian>::Reloc_section* | ||
| 549 | +Output_data_plt_arm<big_endian>::rel_irelative(Symbol_table* symtab, | ||
| 550 | + Layout* layout) | ||
| 551 | +{ | ||
| 552 | + if (this->irelative_rel_ == NULL) | ||
| 553 | + { | ||
| 554 | + // Since irelative relocations goes into 'rel.dyn', we delegate the | ||
| 555 | + // creation of irelative_rel_ to where rel_dyn section gets created. | ||
| 556 | + Target_arm<big_endian>* arm_target = | ||
| 557 | + Target_arm<big_endian>::default_target(); | ||
| 558 | + this->irelative_rel_ = arm_target->rel_irelative_section(layout); | ||
| 559 | + | ||
| 560 | + // Make sure we have a place for the TLSDESC relocations, in | ||
| 561 | + // case we see any later on. | ||
| 562 | + // this->rel_tlsdesc(layout); | ||
| 563 | + if (parameters->doing_static_link()) | ||
| 564 | + { | ||
| 565 | + // A statically linked executable will only have a .rel.plt section to | ||
| 566 | + // hold R_ARM_IRELATIVE relocs for STT_GNU_IFUNC symbols. The library | ||
| 567 | + // will use these symbols to locate the IRELATIVE relocs at program | ||
| 568 | + // startup time. | ||
| 569 | + symtab->define_in_output_data("__rel_iplt_start", NULL, | ||
| 570 | + Symbol_table::PREDEFINED, | ||
| 571 | + this->irelative_rel_, 0, 0, | ||
| 572 | + elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, | ||
| 573 | + elfcpp::STV_HIDDEN, 0, false, true); | ||
| 574 | + symtab->define_in_output_data("__rel_iplt_end", NULL, | ||
| 575 | + Symbol_table::PREDEFINED, | ||
| 576 | + this->irelative_rel_, 0, 0, | ||
| 577 | + elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, | ||
| 578 | + elfcpp::STV_HIDDEN, 0, true, true); | ||
| 579 | + } | ||
| 580 | + } | ||
| 581 | + return this->irelative_rel_; | ||
| 582 | +} | ||
| 583 | + | ||
| 584 | + | ||
| 585 | +// Return the PLT address for a global symbol. | ||
| 586 | + | ||
| 587 | +template<bool big_endian> | ||
| 588 | +uint32_t | ||
| 589 | +Output_data_plt_arm<big_endian>::address_for_global(const Symbol* gsym) const | ||
| 590 | +{ | ||
| 591 | + uint64_t begin_offset = 0; | ||
| 592 | + if (gsym->type() == elfcpp::STT_GNU_IFUNC | ||
| 593 | + && gsym->can_use_relative_reloc(false)) | ||
| 594 | + { | ||
| 595 | + begin_offset = (this->first_plt_entry_offset() + | ||
| 596 | + this->count_ * this->get_plt_entry_size()); | ||
| 597 | + } | ||
| 598 | + return this->address() + begin_offset + gsym->plt_offset(); | ||
| 599 | +} | ||
| 600 | + | ||
| 601 | + | ||
| 602 | +// Return the PLT address for a local symbol. These are always | ||
| 603 | +// IRELATIVE relocs. | ||
| 604 | + | ||
| 605 | +template<bool big_endian> | ||
| 606 | +uint32_t | ||
| 607 | +Output_data_plt_arm<big_endian>::address_for_local( | ||
| 608 | + const Relobj* object, | ||
| 609 | + unsigned int r_sym) const | ||
| 610 | +{ | ||
| 611 | + return (this->address() | ||
| 612 | + + this->first_plt_entry_offset() | ||
| 613 | + + this->count_ * this->get_plt_entry_size() | ||
| 614 | + + object->local_plt_offset(r_sym)); | ||
| 615 | +} | ||
| 616 | + | ||
| 617 | + | ||
| 618 | template<bool big_endian> | ||
| 619 | class Output_data_plt_arm_standard : public Output_data_plt_arm<big_endian> | ||
| 620 | { | ||
| 621 | public: | ||
| 622 | - Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt) | ||
| 623 | - : Output_data_plt_arm<big_endian>(layout, 4, got_plt) | ||
| 624 | + Output_data_plt_arm_standard(Layout* layout, | ||
| 625 | + Arm_output_data_got<big_endian>* got, | ||
| 626 | + Output_data_space* got_plt, | ||
| 627 | + Output_data_space* got_irelative) | ||
| 628 | + : Output_data_plt_arm<big_endian>(layout, 4, got, got_plt, got_irelative) | ||
| 629 | { } | ||
| 630 | |||
| 631 | protected: | ||
| 632 | @@ -7485,8 +7825,11 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of) | ||
| 633 | unsigned char* const oview = of->get_output_view(offset, oview_size); | ||
| 634 | |||
| 635 | const off_t got_file_offset = this->got_plt_->offset(); | ||
| 636 | + gold_assert(got_file_offset + this->got_plt_->data_size() | ||
| 637 | + == this->got_irelative_->offset()); | ||
| 638 | const section_size_type got_size = | ||
| 639 | - convert_to_section_size_type(this->got_plt_->data_size()); | ||
| 640 | + convert_to_section_size_type(this->got_plt_->data_size() | ||
| 641 | + + this->got_irelative_->data_size()); | ||
| 642 | unsigned char* const got_view = of->get_output_view(got_file_offset, | ||
| 643 | got_size); | ||
| 644 | unsigned char* pov = oview; | ||
| 645 | @@ -7505,7 +7848,8 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of) | ||
| 646 | |||
| 647 | unsigned int plt_offset = this->first_plt_entry_offset(); | ||
| 648 | unsigned int got_offset = 12; | ||
| 649 | - const unsigned int count = this->count_; | ||
| 650 | + const unsigned int count = this->count_ + this->irelative_count_; | ||
| 651 | + gold_assert(this->irelative_count_ == this->irelative_data_vec_.size()); | ||
| 652 | for (unsigned int i = 0; | ||
| 653 | i < count; | ||
| 654 | ++i, | ||
| 655 | @@ -7518,8 +7862,33 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of) | ||
| 656 | this->fill_plt_entry(pov, got_address, plt_address, | ||
| 657 | got_offset, plt_offset); | ||
| 658 | |||
| 659 | - // Set the entry in the GOT. | ||
| 660 | - elfcpp::Swap<32, big_endian>::writeval(got_pov, plt_address); | ||
| 661 | + Arm_address value; | ||
| 662 | + if (i < this->count_) | ||
| 663 | + { | ||
| 664 | + // For non-irelative got entries, the value is the beginning of plt. | ||
| 665 | + value = plt_address; | ||
| 666 | + } | ||
| 667 | + else | ||
| 668 | + { | ||
| 669 | + // For irelative got entries, the value is the (global/local) symbol | ||
| 670 | + // address. | ||
| 671 | + const IRelative_data& idata = | ||
| 672 | + this->irelative_data_vec_[i - this->count_]; | ||
| 673 | + if (idata.symbol_is_global_) | ||
| 674 | + { | ||
| 675 | + // Set the entry in the GOT for irelative symbols. The content is | ||
| 676 | + // the address of the ifunc, not the address of plt start. | ||
| 677 | + const Sized_symbol<32>* sized_symbol = idata.u_.global; | ||
| 678 | + gold_assert(sized_symbol->type() == elfcpp::STT_GNU_IFUNC); | ||
| 679 | + value = sized_symbol->value(); | ||
| 680 | + } | ||
| 681 | + else | ||
| 682 | + { | ||
| 683 | + value = idata.u_.local.relobj->local_symbol_value( | ||
| 684 | + idata.u_.local.index, 0); | ||
| 685 | + } | ||
| 686 | + } | ||
| 687 | + elfcpp::Swap<32, big_endian>::writeval(got_pov, value); | ||
| 688 | } | ||
| 689 | |||
| 690 | gold_assert(static_cast<section_size_type>(pov - oview) == oview_size); | ||
| 691 | @@ -7529,6 +7898,7 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of) | ||
| 692 | of->write_output_view(got_file_offset, got_size, got_view); | ||
| 693 | } | ||
| 694 | |||
| 695 | + | ||
| 696 | // Create a PLT entry for a global symbol. | ||
| 697 | |||
| 698 | template<bool big_endian> | ||
| 699 | @@ -7540,20 +7910,58 @@ Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout, | ||
| 700 | return; | ||
| 701 | |||
| 702 | if (this->plt_ == NULL) | ||
| 703 | + this->make_plt_section(symtab, layout); | ||
| 704 | + | ||
| 705 | + this->plt_->add_entry(symtab, layout, gsym); | ||
| 706 | +} | ||
| 707 | + | ||
| 708 | + | ||
| 709 | +// Create the PLT section. | ||
| 710 | +template<bool big_endian> | ||
| 711 | +void | ||
| 712 | +Target_arm<big_endian>::make_plt_section( | ||
| 713 | + Symbol_table* symtab, Layout* layout) | ||
| 714 | +{ | ||
| 715 | + if (this->plt_ == NULL) | ||
| 716 | { | ||
| 717 | - // Create the GOT sections first. | ||
| 718 | + // Create the GOT section first. | ||
| 719 | this->got_section(symtab, layout); | ||
| 720 | |||
| 721 | - this->plt_ = this->make_data_plt(layout, this->got_plt_); | ||
| 722 | + // GOT for irelatives is create along with got.plt. | ||
| 723 | + gold_assert(this->got_ != NULL | ||
| 724 | + && this->got_plt_ != NULL | ||
| 725 | + && this->got_irelative_ != NULL); | ||
| 726 | + this->plt_ = this->make_data_plt(layout, this->got_, this->got_plt_, | ||
| 727 | + this->got_irelative_); | ||
| 728 | |||
| 729 | layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, | ||
| 730 | (elfcpp::SHF_ALLOC | ||
| 731 | | elfcpp::SHF_EXECINSTR), | ||
| 732 | this->plt_, ORDER_PLT, false); | ||
| 733 | } | ||
| 734 | - this->plt_->add_entry(gsym); | ||
| 735 | } | ||
| 736 | |||
| 737 | + | ||
| 738 | +// Make a PLT entry for a local STT_GNU_IFUNC symbol. | ||
| 739 | + | ||
| 740 | +template<bool big_endian> | ||
| 741 | +void | ||
| 742 | +Target_arm<big_endian>::make_local_ifunc_plt_entry( | ||
| 743 | + Symbol_table* symtab, Layout* layout, | ||
| 744 | + Sized_relobj_file<32, big_endian>* relobj, | ||
| 745 | + unsigned int local_sym_index) | ||
| 746 | +{ | ||
| 747 | + if (relobj->local_has_plt_offset(local_sym_index)) | ||
| 748 | + return; | ||
| 749 | + if (this->plt_ == NULL) | ||
| 750 | + this->make_plt_section(symtab, layout); | ||
| 751 | + unsigned int plt_offset = this->plt_->add_local_ifunc_entry(symtab, layout, | ||
| 752 | + relobj, | ||
| 753 | + local_sym_index); | ||
| 754 | + relobj->set_local_plt_offset(local_sym_index, plt_offset); | ||
| 755 | +} | ||
| 756 | + | ||
| 757 | + | ||
| 758 | // Return the number of entries in the PLT. | ||
| 759 | |||
| 760 | template<bool big_endian> | ||
| 761 | @@ -7823,6 +8231,7 @@ Target_arm<big_endian>::Scan::check_non_pic(Relobj* object, | ||
| 762 | case elfcpp::R_ARM_JUMP_SLOT: | ||
| 763 | case elfcpp::R_ARM_ABS32: | ||
| 764 | case elfcpp::R_ARM_ABS32_NOI: | ||
| 765 | + case elfcpp::R_ARM_IRELATIVE: | ||
| 766 | case elfcpp::R_ARM_PC24: | ||
| 767 | // FIXME: The following 3 types are not supported by Android's dynamic | ||
| 768 | // linker. | ||
| 769 | @@ -7853,6 +8262,27 @@ Target_arm<big_endian>::Scan::check_non_pic(Relobj* object, | ||
| 770 | } | ||
| 771 | } | ||
| 772 | |||
| 773 | + | ||
| 774 | +// Return whether we need to make a PLT entry for a relocation of the | ||
| 775 | +// given type against a STT_GNU_IFUNC symbol. | ||
| 776 | + | ||
| 777 | +template<bool big_endian> | ||
| 778 | +bool | ||
| 779 | +Target_arm<big_endian>::Scan::reloc_needs_plt_for_ifunc( | ||
| 780 | + Sized_relobj_file<32, big_endian>* object, | ||
| 781 | + unsigned int r_type) | ||
| 782 | +{ | ||
| 783 | + int flags = Scan::get_reference_flags(r_type); | ||
| 784 | + if (flags & Symbol::TLS_REF) | ||
| 785 | + { | ||
| 786 | + gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"), | ||
| 787 | + object->name().c_str(), r_type); | ||
| 788 | + return false; | ||
| 789 | + } | ||
| 790 | + return flags != 0; | ||
| 791 | +} | ||
| 792 | + | ||
| 793 | + | ||
| 794 | // Scan a relocation for a local symbol. | ||
| 795 | // FIXME: This only handles a subset of relocation types used by Android | ||
| 796 | // on ARM v5te devices. | ||
| 797 | @@ -7874,6 +8304,15 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, | ||
| 798 | return; | ||
| 799 | |||
| 800 | r_type = get_real_reloc_type(r_type); | ||
| 801 | + | ||
| 802 | + // A local STT_GNU_IFUNC symbol may require a PLT entry. | ||
| 803 | + bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC; | ||
| 804 | + if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type)) | ||
| 805 | + { | ||
| 806 | + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); | ||
| 807 | + target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym); | ||
| 808 | + } | ||
| 809 | + | ||
| 810 | switch (r_type) | ||
| 811 | { | ||
| 812 | case elfcpp::R_ARM_NONE: | ||
| 813 | @@ -7898,7 +8337,7 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, | ||
| 814 | // we need to add check_non_pic(object, r_type) here. | ||
| 815 | rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE, | ||
| 816 | output_section, data_shndx, | ||
| 817 | - reloc.get_r_offset()); | ||
| 818 | + reloc.get_r_offset(), is_ifunc); | ||
| 819 | } | ||
| 820 | break; | ||
| 821 | |||
| 822 | @@ -8265,6 +8704,11 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, | ||
| 823 | && strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0) | ||
| 824 | target->got_section(symtab, layout); | ||
| 825 | |||
| 826 | + // A STT_GNU_IFUNC symbol may require a PLT entry. | ||
| 827 | + if (gsym->type() == elfcpp::STT_GNU_IFUNC | ||
| 828 | + && this->reloc_needs_plt_for_ifunc(object, r_type)) | ||
| 829 | + target->make_plt_entry(symtab, layout, gsym); | ||
| 830 | + | ||
| 831 | r_type = get_real_reloc_type(r_type); | ||
| 832 | switch (r_type) | ||
| 833 | { | ||
| 834 | @@ -8309,6 +8753,24 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, | ||
| 835 | } | ||
| 836 | else if ((r_type == elfcpp::R_ARM_ABS32 | ||
| 837 | || r_type == elfcpp::R_ARM_ABS32_NOI) | ||
| 838 | + && gsym->type() == elfcpp::STT_GNU_IFUNC | ||
| 839 | + && gsym->can_use_relative_reloc(false) | ||
| 840 | + && !gsym->is_from_dynobj() | ||
| 841 | + && !gsym->is_undefined() | ||
| 842 | + && !gsym->is_preemptible()) | ||
| 843 | + { | ||
| 844 | + // Use an IRELATIVE reloc for a locally defined STT_GNU_IFUNC | ||
| 845 | + // symbol. This makes a function address in a PIE executable | ||
| 846 | + // match the address in a shared library that it links against. | ||
| 847 | + Reloc_section* rel_irelative = | ||
| 848 | + target->rel_irelative_section(layout); | ||
| 849 | + unsigned int r_type = elfcpp::R_ARM_IRELATIVE; | ||
| 850 | + rel_irelative->add_symbolless_global_addend( | ||
| 851 | + gsym, r_type, output_section, object, | ||
| 852 | + data_shndx, reloc.get_r_offset()); | ||
| 853 | + } | ||
| 854 | + else if ((r_type == elfcpp::R_ARM_ABS32 | ||
| 855 | + || r_type == elfcpp::R_ARM_ABS32_NOI) | ||
| 856 | && gsym->can_use_relative_reloc(false)) | ||
| 857 | { | ||
| 858 | Reloc_section* rel_dyn = target->rel_dyn_section(layout); | ||
| 859 | @@ -8442,7 +8904,13 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, | ||
| 860 | Arm_output_data_got<big_endian>* got = | ||
| 861 | target->got_section(symtab, layout); | ||
| 862 | if (gsym->final_value_is_known()) | ||
| 863 | - got->add_global(gsym, GOT_TYPE_STANDARD); | ||
| 864 | + { | ||
| 865 | + // For a STT_GNU_IFUNC symbol we want the PLT address. | ||
| 866 | + if (gsym->type() == elfcpp::STT_GNU_IFUNC) | ||
| 867 | + got->add_global_plt(gsym, GOT_TYPE_STANDARD); | ||
| 868 | + else | ||
| 869 | + got->add_global(gsym, GOT_TYPE_STANDARD); | ||
| 870 | + } | ||
| 871 | else | ||
| 872 | { | ||
| 873 | // If this symbol is not fully resolved, we need to add a | ||
| 874 | @@ -8452,12 +8920,29 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, | ||
| 875 | || gsym->is_undefined() | ||
| 876 | || gsym->is_preemptible() | ||
| 877 | || (gsym->visibility() == elfcpp::STV_PROTECTED | ||
| 878 | - && parameters->options().shared())) | ||
| 879 | + && parameters->options().shared()) | ||
| 880 | + || (gsym->type() == elfcpp::STT_GNU_IFUNC | ||
| 881 | + && parameters->options().output_is_position_independent())) | ||
| 882 | got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, | ||
| 883 | rel_dyn, elfcpp::R_ARM_GLOB_DAT); | ||
| 884 | else | ||
| 885 | { | ||
| 886 | - if (got->add_global(gsym, GOT_TYPE_STANDARD)) | ||
| 887 | + // For a STT_GNU_IFUNC symbol we want to write the PLT | ||
| 888 | + // offset into the GOT, so that function pointer | ||
| 889 | + // comparisons work correctly. | ||
| 890 | + bool is_new; | ||
| 891 | + if (gsym->type() != elfcpp::STT_GNU_IFUNC) | ||
| 892 | + is_new = got->add_global(gsym, GOT_TYPE_STANDARD); | ||
| 893 | + else | ||
| 894 | + { | ||
| 895 | + is_new = got->add_global_plt(gsym, GOT_TYPE_STANDARD); | ||
| 896 | + // Tell the dynamic linker to use the PLT address | ||
| 897 | + // when resolving relocations. | ||
| 898 | + if (gsym->is_from_dynobj() | ||
| 899 | + && !parameters->options().shared()) | ||
| 900 | + gsym->set_needs_dynsym_value(); | ||
| 901 | + } | ||
| 902 | + if (is_new) | ||
| 903 | rel_dyn->add_global_relative( | ||
| 904 | gsym, elfcpp::R_ARM_RELATIVE, got, | ||
| 905 | gsym->got_offset(GOT_TYPE_STANDARD)); | ||
| 906 | @@ -8919,8 +9404,7 @@ Target_arm<big_endian>::Relocate::relocate( | ||
| 907 | if (gsym->use_plt_offset(Scan::get_reference_flags(r_type))) | ||
| 908 | { | ||
| 909 | // This uses a PLT, change the symbol value. | ||
| 910 | - symval.set_output_value(target->plt_section()->address() | ||
| 911 | - + gsym->plt_offset()); | ||
| 912 | + symval.set_output_value(target->plt_address_for_global(gsym)); | ||
| 913 | psymval = &symval; | ||
| 914 | } | ||
| 915 | else if (gsym->is_weak_undefined()) | ||
| 916 | @@ -8958,6 +9442,13 @@ Target_arm<big_endian>::Relocate::relocate( | ||
| 917 | elfcpp::Elf_types<32>::Elf_WXword r_info = rel.get_r_info(); | ||
| 918 | unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info); | ||
| 919 | thumb_bit = object->local_symbol_is_thumb_function(r_sym) ? 1 : 0; | ||
| 920 | + | ||
| 921 | + if (psymval->is_ifunc_symbol() && object->local_has_plt_offset(r_sym)) | ||
| 922 | + { | ||
| 923 | + symval.set_output_value( | ||
| 924 | + target->plt_address_for_local(object, r_sym)); | ||
| 925 | + psymval = &symval; | ||
| 926 | + } | ||
| 927 | } | ||
| 928 | } | ||
| 929 | else | ||
| 930 | @@ -9936,7 +10427,7 @@ uint64_t | ||
| 931 | Target_arm<big_endian>::do_dynsym_value(const Symbol* gsym) const | ||
| 932 | { | ||
| 933 | gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset()); | ||
| 934 | - return this->plt_section()->address() + gsym->plt_offset(); | ||
| 935 | + return this->plt_address_for_global(gsym); | ||
| 936 | } | ||
| 937 | |||
| 938 | // Map platform-specific relocs to real relocs | ||
| 939 | @@ -11083,8 +11574,7 @@ Target_arm<big_endian>::scan_reloc_for_stub( | ||
| 940 | if (gsym->use_plt_offset(Scan::get_reference_flags(r_type))) | ||
| 941 | { | ||
| 942 | // This uses a PLT, change the symbol value. | ||
| 943 | - symval.set_output_value(this->plt_section()->address() | ||
| 944 | - + gsym->plt_offset()); | ||
| 945 | + symval.set_output_value(this->plt_address_for_global(gsym)); | ||
| 946 | psymval = &symval; | ||
| 947 | target_is_thumb = false; | ||
| 948 | } | ||
| 949 | @@ -12187,8 +12677,13 @@ class Target_arm_nacl : public Target_arm<big_endian> | ||
| 950 | |||
| 951 | protected: | ||
| 952 | virtual Output_data_plt_arm<big_endian>* | ||
| 953 | - do_make_data_plt(Layout* layout, Output_data_space* got_plt) | ||
| 954 | - { return new Output_data_plt_arm_nacl<big_endian>(layout, got_plt); } | ||
| 955 | + do_make_data_plt( | ||
| 956 | + Layout* layout, | ||
| 957 | + Arm_output_data_got<big_endian>* got, | ||
| 958 | + Output_data_space* got_plt, | ||
| 959 | + Output_data_space* got_irelative) | ||
| 960 | + { return new Output_data_plt_arm_nacl<big_endian>( | ||
| 961 | + layout, got, got_plt, got_irelative); } | ||
| 962 | |||
| 963 | private: | ||
| 964 | static const Target::Target_info arm_nacl_info; | ||
| 965 | @@ -12225,8 +12720,12 @@ template<bool big_endian> | ||
| 966 | class Output_data_plt_arm_nacl : public Output_data_plt_arm<big_endian> | ||
| 967 | { | ||
| 968 | public: | ||
| 969 | - Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt) | ||
| 970 | - : Output_data_plt_arm<big_endian>(layout, 16, got_plt) | ||
| 971 | + Output_data_plt_arm_nacl( | ||
| 972 | + Layout* layout, | ||
| 973 | + Arm_output_data_got<big_endian>* got, | ||
| 974 | + Output_data_space* got_plt, | ||
| 975 | + Output_data_space* got_irelative) | ||
| 976 | + : Output_data_plt_arm<big_endian>(layout, 16, got, got_plt, got_irelative) | ||
| 977 | { } | ||
| 978 | |||
| 979 | protected: | ||
| 980 | diff --git a/gold/output.h b/gold/output.h | ||
| 981 | index ba0cdaa..599c2b7 100644 | ||
| 982 | --- a/gold/output.h | ||
| 983 | +++ b/gold/output.h | ||
| 984 | @@ -1714,6 +1714,17 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> | ||
| 985 | address, true, true, false, false)); | ||
| 986 | } | ||
| 987 | |||
| 988 | + void | ||
| 989 | + add_local_relative(Sized_relobj<size, big_endian>* relobj, | ||
| 990 | + unsigned int local_sym_index, unsigned int type, | ||
| 991 | + Output_data* od, unsigned int shndx, Address address, | ||
| 992 | + bool use_plt_offset) | ||
| 993 | + { | ||
| 994 | + this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, | ||
| 995 | + address, true, true, false, | ||
| 996 | + use_plt_offset)); | ||
| 997 | + } | ||
| 998 | + | ||
| 999 | // Add a local relocation which does not use a symbol for the relocation, | ||
| 1000 | // but which gets its addend from a symbol. | ||
| 1001 | |||
| 1002 | -- | ||
| 1003 | 2.7.0 | ||
| 1004 | |||
