@@ -53,8 +53,8 @@ off_t fileSize, maxSize;
53
53
unsigned char * contents = 0 ;
54
54
55
55
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
58
58
59
59
60
60
static unsigned int getPageSize (){
@@ -1260,6 +1260,8 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(map<string, string>& libs)
1260
1260
1261
1261
Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi (shdrDynamic.sh_offset ));
1262
1262
1263
+ unsigned int verNeedNum = 0 ;
1264
+
1263
1265
unsigned int dynStrAddedBytes = 0 ;
1264
1266
1265
1267
for ( ; rdi (dyn->d_tag ) != DT_NULL; dyn++) {
@@ -1272,13 +1274,13 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(map<string, string>& libs)
1272
1274
1273
1275
// technically, the string referred by d_val could be used otherwise, too (although unlikely)
1274
1276
// we'll therefore add a new string
1275
- debug (" resizing .dynstr ..." );
1277
+ debug (" resizing .dynstr ...\n " );
1276
1278
1277
1279
string & newDynStr = replaceSection (" .dynstr" ,
1278
1280
rdi (shdrDynStr.sh_size ) + replacement.size () + 1 + dynStrAddedBytes);
1279
1281
setSubstr (newDynStr, rdi (shdrDynStr.sh_size ) + dynStrAddedBytes, replacement + ' \0 ' );
1280
1282
1281
- dyn->d_un .d_val = shdrDynStr.sh_size + dynStrAddedBytes;
1283
+ wri ( dyn->d_un .d_val , rdi ( shdrDynStr.sh_size ) + dynStrAddedBytes) ;
1282
1284
1283
1285
dynStrAddedBytes += replacement.size () + 1 ;
1284
1286
@@ -1287,6 +1289,57 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(map<string, string>& libs)
1287
1289
debug (" keeping DT_NEEDED entry `%s'\n " , name);
1288
1290
}
1289
1291
}
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
+ }
1290
1343
}
1291
1344
}
1292
1345
@@ -1474,13 +1527,13 @@ static void patchElf()
1474
1527
if (contents[EI_CLASS] == ELFCLASS32 &&
1475
1528
contents[EI_VERSION] == EV_CURRENT)
1476
1529
{
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;
1478
1531
patchElf2 (elfFile);
1479
1532
}
1480
1533
else if (contents[EI_CLASS] == ELFCLASS64 &&
1481
1534
contents[EI_VERSION] == EV_CURRENT)
1482
1535
{
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;
1484
1537
patchElf2 (elfFile);
1485
1538
}
1486
1539
else {
0 commit comments