24
24
#include < sstream>
25
25
#include < stdexcept>
26
26
#include < string>
27
+ #include < unordered_map>
27
28
#include < vector>
28
29
29
30
#include < cassert>
@@ -1584,6 +1585,7 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
1584
1585
unsigned int verNeedNum = 0 ;
1585
1586
1586
1587
unsigned int dynStrAddedBytes = 0 ;
1588
+ std::unordered_map<std::string, Elf_Off> addedStrings;
1587
1589
1588
1590
for ( ; rdi (dyn->d_tag ) != DT_NULL; dyn++) {
1589
1591
if (rdi (dyn->d_tag ) == DT_NEEDED) {
@@ -1594,15 +1596,25 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
1594
1596
1595
1597
debug (" replacing DT_NEEDED entry '%s' with '%s'\n " , name, replacement.c_str ());
1596
1598
1599
+ auto a = addedStrings.find (replacement);
1600
+ // the same replacement string has already been added, reuse it
1601
+ if (a != addedStrings.end ()) {
1602
+ wri (dyn->d_un .d_val , a->second );
1603
+ continue ;
1604
+ }
1605
+
1597
1606
// technically, the string referred by d_val could be used otherwise, too (although unlikely)
1598
1607
// we'll therefore add a new string
1599
1608
debug (" resizing .dynstr ...\n " );
1600
1609
1610
+ // relative location of the new string
1611
+ Elf_Off strOffset = rdi (shdrDynStr.sh_size ) + dynStrAddedBytes;
1601
1612
std::string & newDynStr = replaceSection (" .dynstr" ,
1602
- rdi (shdrDynStr. sh_size ) + replacement.size () + 1 + dynStrAddedBytes );
1603
- setSubstr (newDynStr, rdi (shdrDynStr. sh_size ) + dynStrAddedBytes , replacement + ' \0 ' );
1613
+ strOffset + replacement.size () + 1 );
1614
+ setSubstr (newDynStr, strOffset , replacement + ' \0 ' );
1604
1615
1605
- wri (dyn->d_un .d_val , rdi (shdrDynStr.sh_size ) + dynStrAddedBytes);
1616
+ wri (dyn->d_un .d_val , strOffset);
1617
+ addedStrings[replacement] = strOffset;
1606
1618
1607
1619
dynStrAddedBytes += replacement.size () + 1 ;
1608
1620
@@ -1636,6 +1648,13 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
1636
1648
debug (" found .gnu.version_r with %i entries, strings in %s\n " , verNeedNum, versionRStringsSName.c_str ());
1637
1649
1638
1650
unsigned int verStrAddedBytes = 0 ;
1651
+ // It may be that it is .dynstr again, in which case we must take the already
1652
+ // added bytes into account.
1653
+ if (versionRStringsSName == " .dynstr" )
1654
+ verStrAddedBytes += dynStrAddedBytes;
1655
+ else
1656
+ // otherwise the already added strings can't be reused
1657
+ addedStrings.clear ();
1639
1658
1640
1659
auto need = (Elf_Verneed *)(fileContents->data () + rdi (shdrVersionR.sh_offset ));
1641
1660
while (verNeedNum > 0 ) {
@@ -1645,15 +1664,24 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
1645
1664
auto replacement = i->second ;
1646
1665
1647
1666
debug (" replacing .gnu.version_r entry '%s' with '%s'\n " , file, replacement.c_str ());
1648
- debug (" resizing string section %s ...\n " , versionRStringsSName.c_str ());
1649
1667
1650
- std::string & newVerDynStr = replaceSection (versionRStringsSName,
1651
- rdi (shdrVersionRStrings.sh_size ) + replacement.size () + 1 + verStrAddedBytes);
1652
- setSubstr (newVerDynStr, rdi (shdrVersionRStrings.sh_size ) + verStrAddedBytes, replacement + ' \0 ' );
1668
+ auto a = addedStrings.find (replacement);
1669
+ // the same replacement string has already been added, reuse it
1670
+ if (a != addedStrings.end ()) {
1671
+ wri (need->vn_file , a->second );
1672
+ } else {
1673
+ debug (" resizing string section %s ...\n " , versionRStringsSName.c_str ());
1674
+
1675
+ Elf_Off strOffset = rdi (shdrVersionRStrings.sh_size ) + verStrAddedBytes;
1676
+ std::string & newVerDynStr = replaceSection (versionRStringsSName,
1677
+ strOffset + replacement.size () + 1 );
1678
+ setSubstr (newVerDynStr, strOffset, replacement + ' \0 ' );
1653
1679
1654
- wri (need->vn_file , rdi (shdrVersionRStrings.sh_size ) + verStrAddedBytes);
1680
+ wri (need->vn_file , strOffset);
1681
+ addedStrings[replacement] = strOffset;
1655
1682
1656
- verStrAddedBytes += replacement.size () + 1 ;
1683
+ verStrAddedBytes += replacement.size () + 1 ;
1684
+ }
1657
1685
1658
1686
changed = true ;
1659
1687
} else {
0 commit comments