Merge branch 'cdugz-master'

This commit is contained in:
Eelco Dolstra
2014-04-24 16:27:54 +02:00
3 changed files with 132 additions and 3 deletions

View File

@@ -144,6 +144,10 @@ public:
string getInterpreter();
string getSoname();
void setSoname(const string & newSoname);
void setInterpreter(const string & newInterpreter);
typedef enum { rpPrint, rpShrink, rpSet } RPathOp;
@@ -871,6 +875,89 @@ string ElfFile<ElfFileParamNames>::getInterpreter()
return string((char *) contents + rdi(shdr.sh_offset), rdi(shdr.sh_size));
}
template<ElfFileParams>
string ElfFile<ElfFileParamNames>::getSoname()
{
Elf_Shdr & shdrDynamic = findSection(".dynamic");
Elf_Shdr & shdrDynStr = findSection(".dynstr");
char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset);
/* 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");
/* 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));
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!");
}
else {
return soname;
}
}
template<ElfFileParams>
void ElfFile<ElfFileParamNames>::setSoname(const string & newSoname)
{
Elf_Shdr & shdrDynamic = findSection(".dynamic");
Elf_Shdr & shdrDynStr = findSection(".dynstr");
char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset);
/* 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");
/* 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));
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!");
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;
}
}
}
template<ElfFileParams>
void ElfFile<ElfFileParamNames>::setInterpreter(const string & newInterpreter)
@@ -1090,6 +1177,9 @@ void ElfFile<ElfFileParamNames>::removeNeeded(set<string> libs)
static bool printInterpreter = false;
static bool printSoname = false;
static bool setSoname = false;
static string newSoname;
static string newInterpreter;
static bool shrinkRPath = false;
@@ -1107,6 +1197,12 @@ static void patchElf2(ElfFile & elfFile, mode_t fileMode)
if (printInterpreter)
printf("%s\n", elfFile.getInterpreter().c_str());
if (printSoname)
printf("%s\n", elfFile.getSoname().c_str());
if (setSoname)
elfFile.setSoname(newSoname);
if (newInterpreter != "")
elfFile.setInterpreter(newInterpreter);
@@ -1129,7 +1225,7 @@ static void patchElf2(ElfFile & elfFile, mode_t fileMode)
static void patchElf()
{
if (!printInterpreter && !printRPath)
if (!printInterpreter && !printRPath && !printSoname)
debug("patching ELF file `%s'\n", fileName.c_str());
mode_t fileMode;
@@ -1166,6 +1262,8 @@ void showHelp(const string & progName)
fprintf(stderr, "syntax: %s\n\
[--set-interpreter FILENAME]\n\
[--print-interpreter]\n\
[--print-soname]\t\tPrints 'DT_SONAME' entry of .dynamic section. Raises an error if DT_SONAME doesn't exist\n\
[--set-soname SONAME]\t\tSets 'DT_SONAME' entry to SONAME. Raises an error if DT_SONAME doesn't exist\n\
[--set-rpath RPATH]\n\
[--shrink-rpath]\n\
[--print-rpath]\n\
@@ -1196,6 +1294,14 @@ int main(int argc, char * * argv)
else if (arg == "--print-interpreter") {
printInterpreter = true;
}
else if (arg == "--print-soname") {
printSoname = true;
}
else if (arg == "--set-soname") {
if (++i == argc) error("missing argument");
setSoname = true;
newSoname = argv[i];
}
else if (arg == "--shrink-rpath") {
shrinkRPath = true;
}

View File

@@ -2,7 +2,7 @@ check_PROGRAMS = simple main main-scoped big-dynstr
TESTS = plain-fail.sh plain-run.sh shrink-rpath.sh set-interpreter-short.sh \
set-interpreter-long.sh set-rpath.sh no-rpath.sh big-dynstr.sh \
set-rpath-library.sh
set-rpath-library.sh soname.sh
EXTRA_DIST = no-rpath $(TESTS)
TESTS_ENVIRONMENT = PATCHELF_DEBUG=1
@@ -44,7 +44,7 @@ big_dynstr_LDFLAGS = $(LDFLAGS_local)
# - without libtool, only archives (static libraries) can be built by automake
# - with libtool, it is difficult to control options
# - with libtool, it is not possible to compile convenience *dynamic* libraries :-(
check_PROGRAMS += libfoo.so libfoo-scoped.so libbar.so libbar-scoped.so
check_PROGRAMS += libfoo.so libfoo-scoped.so libbar.so libbar-scoped.so libsimple.so
libfoo_so_SOURCES = foo.c
libfoo_so_LDADD = -lbar $(AM_LDADD)
@@ -62,3 +62,5 @@ libbar_so_LDFLAGS = $(LDFLAGS_sharedlib) -Wl,-rpath,`pwd`/no-such-path
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

21
tests/soname.sh Executable file
View File

@@ -0,0 +1,21 @@
#! /bin/sh -e
SCRATCH=scratch/$(basename $0 .sh)
rm -rf ${SCRATCH}
mkdir -p ${SCRATCH}
cp libsimple.so ${SCRATCH}/
# print and set 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
../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
echo "failed --set-soname test. Expected newSoname: libsimple.so.1.1, got: $newSoname"
exit 1
fi