* icf.cc (get_rel_addend): New function. (get_section_contents): Move merge section addend computation to a new function. Ignore negative values for SHT_REL and SHT_RELA addends. Fix bug to not read past the length of the section. diff --git a/gold/icf.cc b/gold/icf.cc index 96b7f2d..4242a14 100644 --- a/gold/icf.cc +++ b/gold/icf.cc @@ -213,6 +213,45 @@ preprocess_for_unique_sections(const std::vector& id_section, } } +// For SHF_MERGE sections that use REL relocations, the addend is stored in +// the text section at the relocation offset. Read the addend value given +// the pointer to the addend in the text section and the addend size. +// Update the addend value if a valid addend is found. +// Parameters: +// RELOC_ADDEND_PTR : Pointer to the addend in the text section. +// ADDEND_SIZE : The size of the addend. +// RELOC_ADDEND_VALUE : Pointer to the addend that is updated. + +inline void +get_rel_addend(const unsigned char* reloc_addend_ptr, + const unsigned int addend_size, + uint64_t* reloc_addend_value) +{ + switch (addend_size) + { + case 0: + break; + case 1: + *reloc_addend_value = + read_from_pointer<8>(reloc_addend_ptr); + break; + case 2: + *reloc_addend_value = + read_from_pointer<16>(reloc_addend_ptr); + break; + case 4: + *reloc_addend_value = + read_from_pointer<32>(reloc_addend_ptr); + break; + case 8: + *reloc_addend_value = + read_from_pointer<64>(reloc_addend_ptr); + break; + default: + gold_unreachable(); + } +} + // This returns the buffer containing the section's contents, both // text and relocs. Relocs are differentiated as those pointing to // sections that could be folded and those that cannot. Only relocs @@ -397,58 +436,36 @@ get_section_contents(bool first_iteration, uint64_t entsize = (it_v->first)->section_entsize(it_v->second); long long offset = it_a->first; - - unsigned long long addend = it_a->second; - // Ignoring the addend when it is a negative value. See the - // comments in Merged_symbol_value::Value in object.h. - if (addend < 0xffffff00) - offset = offset + addend; - - // For SHT_REL relocation sections, the addend is stored in the - // text section at the relocation offset. - uint64_t reloc_addend_value = 0; + // Handle SHT_RELA and SHT_REL addends, only one of these + // addends exists. + // Get the SHT_RELA addend. For RELA relocations, we have + // the addend from the relocation. + uint64_t reloc_addend_value = it_a->second; + + // Handle SHT_REL addends. + // For REL relocations, we need to fetch the addend from the + // section contents. const unsigned char* reloc_addend_ptr = contents + static_cast(*it_o); - switch(*it_addend_size) - { - case 0: - { - break; - } - case 1: - { - reloc_addend_value = - read_from_pointer<8>(reloc_addend_ptr); - break; - } - case 2: - { - reloc_addend_value = - read_from_pointer<16>(reloc_addend_ptr); - break; - } - case 4: - { - reloc_addend_value = - read_from_pointer<32>(reloc_addend_ptr); - break; - } - case 8: - { - reloc_addend_value = - read_from_pointer<64>(reloc_addend_ptr); - break; - } - default: - gold_unreachable(); - } - offset = offset + reloc_addend_value; + + // Update the addend value with the SHT_REL addend if + // available. + get_rel_addend(reloc_addend_ptr, *it_addend_size, + &reloc_addend_value); + + // Ignore the addend when it is a negative value. See the + // comments in Merged_symbol_value::value in object.h. + if (reloc_addend_value < 0xffffff00) + offset = offset + reloc_addend_value; section_size_type secn_len; + const unsigned char* str_contents = (it_v->first)->section_contents(it_v->second, &secn_len, false) + offset; + gold_assert (offset < (long long) secn_len); + if ((secn_flags & elfcpp::SHF_STRINGS) != 0) { // String merge section. @@ -489,10 +506,14 @@ get_section_contents(bool first_iteration, } else { - // Use the entsize to determine the length. - buffer.append(reinterpret_cast secn_len) + bufsize = secn_len - offset; + buffer.append(reinterpret_cast(str_contents), - entsize); + bufsize); } buffer.append("@"); }