From 764dacc6d6e54e343bbe62ea05e3df7dbd175e2c Mon Sep 17 00:00:00 2001 From: darealshinji Date: Mon, 13 Jul 2015 19:52:35 +0200 Subject: Create new soname entry if shlib is missing one, merge modifySoname() and getSoname() Basically this is just a modified copy of the rpath code --- src/patchelf.cc | 127 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 69 insertions(+), 58 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index df75593..35c3ece 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -154,9 +154,9 @@ public: string getInterpreter(); - string getSoname(); + typedef enum { printSoname, replaceSoname } sonameMode; - void setSoname(const string & newSoname); + void modifySoname(sonameMode op, const string & newSoname); void setInterpreter(const string & newInterpreter); @@ -899,8 +899,13 @@ string ElfFile::getInterpreter() } template -string ElfFile::getSoname() +void ElfFile::modifySoname(sonameMode op, const string & newSoname) { + if (rdi(hdr->e_type) != ET_DYN) { + debug("this is not a dynamic library\n"); + return; + } + Elf_Shdr & shdrDynamic = findSection(".dynamic"); Elf_Shdr & shdrDynStr = findSection(".dynstr"); char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset); @@ -909,76 +914,82 @@ string ElfFile::getSoname() Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset)); Elf_Addr strTabAddr = 0; for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) - if (rdi(dyn->d_tag) == DT_STRTAB) strTabAddr = rdi(dyn->d_un.d_ptr); + if (rdi(dyn->d_tag) == DT_STRTAB) + strTabAddr = rdi(dyn->d_un.d_ptr); if (!strTabAddr) error("strange: no string table"); /* We assume that the virtual address in the DT_STRTAB entry of the dynamic section corresponds to the .dynstr section. */ assert(strTabAddr == rdi(shdrDynStr.sh_addr)); - Elf_Dyn * dynSoname = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset)); + /* Walk through the dynamic section, look for the DT_SONAME entry. */ + static vector neededLibs; + dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset)); + Elf_Dyn * dynSoname = 0; char * soname = 0; - for ( ; rdi(dynSoname->d_tag) != DT_NULL; dynSoname++) { - if (rdi(dynSoname->d_tag) == DT_SONAME) { - soname = strTab + rdi(dynSoname->d_un.d_val); - break; + for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { + if (rdi(dyn->d_tag) == DT_SONAME) { + dynSoname = dyn; + soname = strTab + rdi(dyn->d_un.d_val); + } else if (rdi(dyn->d_tag) == DT_INIT) + neededLibs.push_back(string(strTab + rdi(dyn->d_un.d_val))); + } + + if (op == printSoname) { + if (soname) { + if (string(soname ? soname : "") == "") + debug("DT_SONAME is empty\n"); + else + printf("%s\n", soname); + } else { + debug("no DT_SONAME found\n"); } + return; } - if (rdi(dynSoname->d_tag) == DT_NULL) - error("Specified ELF file does not contain any DT_SONAME entry in .dynamic section!"); + if (string(soname ? soname : "") == newSoname) { + debug("current and proposed new SONAMEs are equal keeping DT_SONAME entry\n"); + return; + } - return soname; -} + /* Zero out the previous SONAME */ + unsigned int sonameSize = 0; + if (soname) { + sonameSize = strlen(soname); + memset(soname, 'X', sonameSize); + } -template -void ElfFile::setSoname(const string & newSoname) -{ - Elf_Shdr & shdrDynamic = findSection(".dynamic"); - Elf_Shdr & shdrDynStr = findSection(".dynstr"); - char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset); + debug("new SONAME is `%s'\n", newSoname.c_str()); - /* Find the DT_STRTAB entry in the dynamic section. */ - Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset)); - Elf_Addr strTabAddr = 0; - for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) - if (rdi(dyn->d_tag) == DT_STRTAB) strTabAddr = rdi(dyn->d_un.d_ptr); - if (!strTabAddr) error("strange: no string table"); + /* Grow the .dynstr section to make room for the new SONAME. */ + debug("SONAME is too long, resizing...\n"); - /* We assume that the virtual address in the DT_STRTAB entry - of the dynamic section corresponds to the .dynstr section. */ - assert(strTabAddr == rdi(shdrDynStr.sh_addr)); + string & newDynStr = replaceSection(".dynstr", rdi(shdrDynStr.sh_size) + newSoname.size() + 1); + setSubstr(newDynStr, rdi(shdrDynStr.sh_size), newSoname + '\0'); - Elf_Dyn * dynSoname = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset)); - char * soname = 0; - for ( ; rdi(dynSoname->d_tag) != DT_NULL; dynSoname++) { - if (rdi(dynSoname->d_tag) == DT_SONAME) { - soname = strTab + rdi(dynSoname->d_un.d_val); - break; - } - } - if (rdi(dynSoname->d_tag) == DT_NULL) - error("Specified ELF file does not contain any DT_SONAME entry in .dynamic section!"); + /* Update the DT_SONAME entry. */ + if (dynSoname) { + dynSoname->d_un.d_val = shdrDynStr.sh_size; + } else { + /* There is no DT_SONAME entry in the .dynamic section, so we + have to grow the .dynamic section. */ + string & newDynamic = replaceSection(".dynamic", rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn)); - if (newSoname.size() <= strlen(soname)) { - debug("old soname: `%s', new soname: `%s'\n", soname, newSoname.c_str()); - strcpy(soname, newSoname.c_str()); - changed = true; - } - else { - /* Grow the .dynstr section to make room for the new DT_SONAME */ - debug("new soname is too long, resizing .dynstr section...\n"); - - string & newDynStr = replaceSection(".dynstr", - rdi(shdrDynStr.sh_size) + newSoname.size() + 1); - setSubstr(newDynStr, rdi(shdrDynStr.sh_size), newSoname + '\0'); - /* Update the DT_SONAME entry, if any */ - if (dynSoname) { - debug("old soname: `%s', new soname: `%s'\n", soname, newSoname.c_str()); - dynSoname->d_un.d_val = shdrDynStr.sh_size; - changed = true; - } + 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 one. */ + setSubstr(newDynamic, sizeof(Elf_Dyn), string(newDynamic, 0, sizeof(Elf_Dyn) * (idx + 1))); + + /* Add the DT_SONAME entry at the top. */ + Elf_Dyn newDyn; + wri(newDyn.d_tag, DT_SONAME); + newDyn.d_un.d_val = shdrDynStr.sh_size; + setSubstr(newDynamic, 0, string((char *)&newDyn, sizeof(Elf_Dyn))); } + + changed = true; } template @@ -1351,10 +1362,10 @@ static void patchElf2(ElfFile & elfFile, mode_t fileMode) printf("%s\n", elfFile.getInterpreter().c_str()); if (printSoname) - printf("%s\n", elfFile.getSoname().c_str()); + elfFile.modifySoname(elfFile.printSoname, ""); if (setSoname) - elfFile.setSoname(newSoname); + elfFile.modifySoname(elfFile.replaceSoname, newSoname); if (newInterpreter != "") elfFile.setInterpreter(newInterpreter); -- cgit v0.12 From 453660e7db8a1889627bba17b5606ad8a035c23c Mon Sep 17 00:00:00 2001 From: darealshinji Date: Mon, 13 Jul 2015 19:53:38 +0200 Subject: tests: build libsimple without soname --- tests/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 190212c..284eb80 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -94,7 +94,7 @@ libbar_scoped_so_SOURCES = bar.c libbar_scoped_so_LDFLAGS = $(LDFLAGS_sharedlib) libsimple_so_SOURCES = simple.c -libsimple_so_LDFLAGS = $(LDFLAGS_sharedlib) -Wl,-soname,libsimple.so.1.0 +libsimple_so_LDFLAGS = $(LDFLAGS_sharedlib) no_rpath_SOURCES = no-rpath.c # no -fpic for no-rpath.o -- cgit v0.12 From d4720dcb722215dbdae4749e306c6d3f9a747e83 Mon Sep 17 00:00:00 2001 From: darealshinji Date: Mon, 13 Jul 2015 19:54:30 +0200 Subject: soname test: set an initial DT_SONAME entry --- tests/soname.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/soname.sh b/tests/soname.sh index f81e8ed..4a8fb96 100755 --- a/tests/soname.sh +++ b/tests/soname.sh @@ -6,13 +6,22 @@ mkdir -p ${SCRATCH} cp libsimple.so ${SCRATCH}/ -# print and set DT_SONAME +# set an initial DT_SONAME entry +../src/patchelf --set-soname libsimple.so.1.0 ${SCRATCH}/libsimple.so +newSoname=$(../src/patchelf --print-soname ${SCRATCH}/libsimple.so) +if test "$newSoname" != libsimple.so.1.0; then + echo "failed --set-soname test. Expected newSoname: libsimple.so.1.0, got: $newSoname" + exit 1 +fi + +# print DT_SONAME soname=$(../src/patchelf --print-soname ${SCRATCH}/libsimple.so) if test "$soname" != libsimple.so.1.0; then echo "failed --print-soname test. Expected soname: libsimple.so.1.0, got: $soname" exit 1 fi +# replace DT_SONAME entry ../src/patchelf --set-soname libsimple.so.1.1 ${SCRATCH}/libsimple.so newSoname=$(../src/patchelf --print-soname ${SCRATCH}/libsimple.so) if test "$newSoname" != libsimple.so.1.1; then -- cgit v0.12