2016-02-05 Sriraman Tallam <tmsriram@google.com>

* 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.

Fix bug related to addend computation for MERGE sections.
This commit is contained in:
Sriraman Tallam 2016-02-05 15:07:45 -08:00
parent c34c98ed62
commit 84d543b7ed
2 changed files with 74 additions and 46 deletions

View file

@ -1,3 +1,10 @@
2016-02-05 Sriraman Tallam <tmsriram@google.com>
* 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.
2016-02-05 Cary Coutant <ccoutant@gmail.com>
Andrew Senkevich <andrew.senkevich@intel.com>

View file

@ -213,6 +213,45 @@ preprocess_for_unique_sections(const std::vector<Section_id>& 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;
// 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;
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_REL addends.
// For REL relocations, we need to fetch the addend from the
// section contents.
const unsigned char* reloc_addend_ptr =
contents + static_cast<unsigned long long>(*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.
// Use the entsize to determine the length to copy.
uint64_t bufsize = entsize;
// If entsize is too big, copy all the remaining bytes.
if ((offset + entsize) > secn_len)
bufsize = secn_len - offset;
buffer.append(reinterpret_cast<const
char*>(str_contents),
entsize);
bufsize);
}
buffer.append("@");
}