@@ -53,8 +53,8 @@ off_t fileSize, maxSize;
5353unsigned char * contents = 0 ;
5454
5555
56- #define ElfFileParams class Elf_Ehdr , class Elf_Phdr , class Elf_Shdr , class Elf_Addr , class Elf_Off , class Elf_Dyn , class Elf_Sym
57- #define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym
56+ #define ElfFileParams class Elf_Ehdr , class Elf_Phdr , class Elf_Shdr , class Elf_Addr , class Elf_Off , class Elf_Dyn , class Elf_Sym , class Elf_Verneed
57+ #define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed
5858
5959
6060static unsigned int getPageSize (){
@@ -1260,6 +1260,8 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(map<string, string>& libs)
12601260
12611261 Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi (shdrDynamic.sh_offset ));
12621262
1263+ unsigned int verNeedNum = 0 ;
1264+
12631265 unsigned int dynStrAddedBytes = 0 ;
12641266
12651267 for ( ; rdi (dyn->d_tag ) != DT_NULL; dyn++) {
@@ -1272,13 +1274,13 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(map<string, string>& libs)
12721274
12731275 // technically, the string referred by d_val could be used otherwise, too (although unlikely)
12741276 // we'll therefore add a new string
1275- debug (" resizing .dynstr ..." );
1277+ debug (" resizing .dynstr ...\n " );
12761278
12771279 string & newDynStr = replaceSection (" .dynstr" ,
12781280 rdi (shdrDynStr.sh_size ) + replacement.size () + 1 + dynStrAddedBytes);
12791281 setSubstr (newDynStr, rdi (shdrDynStr.sh_size ) + dynStrAddedBytes, replacement + ' \0 ' );
12801282
1281- dyn->d_un .d_val = shdrDynStr.sh_size + dynStrAddedBytes;
1283+ wri ( dyn->d_un .d_val , rdi ( shdrDynStr.sh_size ) + dynStrAddedBytes) ;
12821284
12831285 dynStrAddedBytes += replacement.size () + 1 ;
12841286
@@ -1287,6 +1289,57 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(map<string, string>& libs)
12871289 debug (" keeping DT_NEEDED entry `%s'\n " , name);
12881290 }
12891291 }
1292+ if (rdi (dyn->d_tag ) == DT_VERNEEDNUM) {
1293+ verNeedNum = rdi (dyn->d_un .d_val );
1294+ }
1295+ }
1296+
1297+ // If a replaced library uses symbol versions, then there will also be
1298+ // references to it in the "version needed" table, and these also need to
1299+ // be replaced.
1300+
1301+ if (verNeedNum) {
1302+ Elf_Shdr & shdrVersionR = findSection (" .gnu.version_r" );
1303+ // The filename strings in the .gnu.version_r are different from the
1304+ // ones in .dynamic: instead of being in .dynstr, they're in some
1305+ // arbitrary section and we have to look in ->sh_link to figure out
1306+ // which one.
1307+ Elf_Shdr & shdrVersionRStrings = shdrs[rdi (shdrVersionR.sh_link )];
1308+ // this is where we find the actual filename strings
1309+ char * verStrTab = (char *) contents + rdi (shdrVersionRStrings.sh_offset );
1310+ // and we also need the name of the section containing the strings, so
1311+ // that we can pass it to replaceSection
1312+ string versionRStringsSName = getSectionName (shdrVersionRStrings);
1313+
1314+ debug (" found .gnu.version_r with %i entries, strings in %s\n " , verNeedNum, versionRStringsSName.c_str ());
1315+
1316+ unsigned int verStrAddedBytes = 0 ;
1317+
1318+ Elf_Verneed * need = (Elf_Verneed *) (contents + rdi (shdrVersionR.sh_offset ));
1319+ while (verNeedNum > 0 ) {
1320+ char * file = verStrTab + rdi (need->vn_file );
1321+ if (libs.find (file) != libs.end ()) {
1322+ const string & replacement = libs[file];
1323+
1324+ debug (" replacing .gnu.version_r entry `%s' with `%s'\n " , file, replacement.c_str ());
1325+ debug (" resizing string section %s ...\n " , versionRStringsSName.c_str ());
1326+
1327+ string & newVerDynStr = replaceSection (versionRStringsSName,
1328+ rdi (shdrVersionRStrings.sh_size ) + replacement.size () + 1 + verStrAddedBytes);
1329+ setSubstr (newVerDynStr, rdi (shdrVersionRStrings.sh_size ) + verStrAddedBytes, replacement + ' \0 ' );
1330+
1331+ wri (need->vn_file , rdi (shdrVersionRStrings.sh_size ) + verStrAddedBytes);
1332+
1333+ verStrAddedBytes += replacement.size () + 1 ;
1334+
1335+ changed = true ;
1336+ } else {
1337+ debug (" keeping .gnu.version_r entry `%s'\n " , file);
1338+ }
1339+ // the Elf_Verneed structures form a linked list, so jump to next entry
1340+ need = (Elf_Verneed *) (contents + rdi (shdrVersionR.sh_offset ) + rdi (need->vn_next ));
1341+ --verNeedNum;
1342+ }
12901343 }
12911344}
12921345
@@ -1474,13 +1527,13 @@ static void patchElf()
14741527 if (contents[EI_CLASS] == ELFCLASS32 &&
14751528 contents[EI_VERSION] == EV_CURRENT)
14761529 {
1477- ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym> elfFile;
1530+ ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed > elfFile;
14781531 patchElf2 (elfFile);
14791532 }
14801533 else if (contents[EI_CLASS] == ELFCLASS64 &&
14811534 contents[EI_VERSION] == EV_CURRENT)
14821535 {
1483- ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym> elfFile;
1536+ ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed > elfFile;
14841537 patchElf2 (elfFile);
14851538 }
14861539 else {
0 commit comments