summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2014-04-24 16:32:05 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2014-04-24 16:32:05 +0200
commit7b515b5596a9be1df0709de427494d01fd08e7fc (patch)
tree4e4bda932de5656dd3d318dc637e63964e8757dc /src
parentf5194e51dc228e1ec10506118c44a5896ce249d8 (diff)
parentae5c6775e4d6e12ddc1c94e93fd4177f8f830f08 (diff)
Merge branch 'master' of github.com:rgcjonas/patchelf
Diffstat (limited to 'src')
-rw-r--r--src/patchelf.cc112
1 files changed, 111 insertions, 1 deletions
diff --git a/src/patchelf.cc b/src/patchelf.cc
index 0aad3e3..6359a04 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -154,7 +154,11 @@ public:
void modifyRPath(RPathOp op, string newRPath);
+ void addNeeded(set<string> libs);
+
void removeNeeded(set<string> libs);
+
+ void replaceNeeded(map<string, string>& libs);
private:
@@ -1175,6 +1179,98 @@ void ElfFile<ElfFileParamNames>::removeNeeded(set<string> libs)
memset(last, 0, sizeof(Elf_Dyn) * (dyn - last));
}
+template<ElfFileParams>
+void ElfFile<ElfFileParamNames>::replaceNeeded(map<string, string>& libs)
+{
+ if (libs.empty()) return;
+
+ Elf_Shdr & shdrDynamic = findSection(".dynamic");
+ Elf_Shdr & shdrDynStr = findSection(".dynstr");
+ char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset);
+
+ Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset));
+
+ unsigned int dynStrAddedBytes = 0;
+
+ for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
+ if (rdi(dyn->d_tag) == DT_NEEDED) {
+ char * name = strTab + rdi(dyn->d_un.d_val);
+ if (libs.find(name) != libs.end()) {
+ const string & replacement = libs[name];
+
+ debug("replacing DT_NEEDED entry `%s' with `%s'\n", name, replacement.c_str());
+
+ // technically, the string referred by d_val could be used otherwise, too (although unlikely)
+ // we'll therefore add a new string
+ debug("resizing .dynstr ...");
+
+ string & newDynStr = replaceSection(".dynstr",
+ rdi(shdrDynStr.sh_size) + replacement.size() + 1 + dynStrAddedBytes);
+ setSubstr(newDynStr, rdi(shdrDynStr.sh_size) + dynStrAddedBytes, replacement + '\0');
+
+ dyn->d_un.d_val = shdrDynStr.sh_size + dynStrAddedBytes;
+
+ dynStrAddedBytes += replacement.size() + 1;
+
+ changed = true;
+ } else {
+ debug("keeping DT_NEEDED entry `%s'\n", name);
+ }
+ }
+ }
+}
+
+template<ElfFileParams>
+void ElfFile<ElfFileParamNames>::addNeeded(set<string> libs)
+{
+ if (libs.empty()) return;
+
+ Elf_Shdr & shdrDynamic = findSection(".dynamic");
+ Elf_Shdr & shdrDynStr = findSection(".dynstr");
+ char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset);
+
+ Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset));
+
+ /* add all new libs to the dynstr string table */
+ unsigned int length = 0;
+ for (set<string>::iterator it = libs.begin(); it != libs.end(); it++) {
+ length += it->size() + 1;
+ }
+
+ string & newDynStr = replaceSection(".dynstr",
+ rdi(shdrDynStr.sh_size) + length + 1);
+ set<Elf64_Xword> libStrings;
+ unsigned int pos = 0;
+ for (set<string>::iterator it = libs.begin(); it != libs.end(); it++) {
+ setSubstr(newDynStr, rdi(shdrDynStr.sh_size) + pos, *it + '\0');
+ libStrings.insert(rdi(shdrDynStr.sh_size) + pos);
+ pos += it->size() + 1;
+ }
+
+ /* add all new needed entries to the dynamic section */
+ string & newDynamic = replaceSection(".dynamic",
+ rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn) * libs.size());
+
+ unsigned int idx = 0;
+ for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
+ debug("DT_NULL index is %d\n", idx);
+
+ /* Shift all entries down by the number of new entries. */
+ setSubstr(newDynamic, sizeof(Elf_Dyn) * libs.size(),
+ string(newDynamic, 0, sizeof(Elf_Dyn) * (idx + 1)));
+
+ /* Add the DT_NEEDED entries at the top. */
+ unsigned int i = 0;
+ for (set<Elf64_Xword>::iterator it = libStrings.begin(); it != libStrings.end(); it++, i++) {
+ Elf_Dyn newDyn;
+ wri(newDyn.d_tag, DT_NEEDED);
+ wri(newDyn.d_un.d_val, *it);
+ setSubstr(newDynamic, i * sizeof(Elf_Dyn), string((char *) &newDyn, sizeof(Elf_Dyn)));
+ }
+
+ changed = true;
+}
+
static bool printInterpreter = false;
static bool printSoname = false;
@@ -1187,7 +1283,8 @@ static bool setRPath = false;
static bool printRPath = false;
static string newRPath;
static set<string> neededLibsToRemove;
-
+static map<string, string> neededLibsToReplace;
+static set<string> neededLibsToAdd;
template<class ElfFile>
static void patchElf2(ElfFile & elfFile, mode_t fileMode)
@@ -1215,6 +1312,8 @@ static void patchElf2(ElfFile & elfFile, mode_t fileMode)
elfFile.modifyRPath(elfFile.rpSet, newRPath);
elfFile.removeNeeded(neededLibsToRemove);
+ elfFile.replaceNeeded(neededLibsToReplace);
+ elfFile.addNeeded(neededLibsToAdd);
if (elfFile.isChanged()){
elfFile.rewriteSections();
@@ -1268,7 +1367,9 @@ void showHelp(const string & progName)
[--shrink-rpath]\n\
[--print-rpath]\n\
[--force-rpath]\n\
+ [--add-needed LIBRARY]\n\
[--remove-needed LIBRARY]\n\
+ [--replace-needed LIBRARY NEW_LIBRARY]\n\
[--debug]\n\
[--version]\n\
FILENAME\n", progName.c_str());
@@ -1327,10 +1428,19 @@ int main(int argc, char * * argv)
added. */
forceRPath = true;
}
+ else if (arg == "--add-needed") {
+ if (++i == argc) error("missing argument");
+ neededLibsToAdd.insert(argv[i]);
+ }
else if (arg == "--remove-needed") {
if (++i == argc) error("missing argument");
neededLibsToRemove.insert(argv[i]);
}
+ else if (arg == "--replace-needed") {
+ if (i+2 >= argc) error("missing argument(s)");
+ neededLibsToReplace[ argv[i+1] ] = argv[i+2];
+ i += 2;
+ }
else if (arg == "--debug") {
debugMode = true;
}