This is the mail archive of the
libc-hacker@cygnus.com
mailing list for the glibc project.
Re: changing embedded RPATH in existing executables.
- To: geoffk@ozemail.com.au
- Subject: Re: changing embedded RPATH in existing executables.
- From: <peeter_joot@VNET.IBM.COM> (peeter joot)
- Date: Fri, 30 Apr 1999 16:14:44 -0400 (EDT)
- Cc: peeterj@ca.ibm.com, egcs@cygnus.com, libc-hacker@cygnus.com, linux-gcc@vger.rutgers.edu
- Reply-To: <peeter_joot@VNET.IBM.COM>
> _Changing_ is a little tricky, but the attached program strips rpaths
> from executables (I find it essential for debugging the binutils).
> It's endian-dependent, if you want this for x86 you can just change
> the occurrences of 'MSB' to 'LSB' and compile (I should really fix
> that).
Hi Geoff,
With your program as a guide (and some peeks into libbfd, elf.h, a bit
of the glibc dynamic loader code, objdump, and a hex-editor) I was able to
figure out enough to find and change the rpath string. That was fun!
This program assumes (unlike your original program) that there is only
one DT_RPATH tag in the dynamic section as even with multiple '-Wl,-rpath,'
commands in the link this seems to occur (they all get concatonated into
a : separated path).
Thanks for your help. If you want to use this on non-x86 you have to change
the occurances of LSB back to MSB:)
Peeter
--
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <elf.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
/* Reads an ELF file, and reads or alters the RPATH setting. */
int
main(int argc, char **argv)
{
int fd;
Elf32_Ehdr ehdr;
int i;
Elf32_Phdr phdr;
Elf32_Shdr shdr;
Elf32_Dyn *dyns;
int rpathoff;
char * strtab;
char * rpath;
int rpathlen;
int oflags;
if (argc != 2 && argc != 3)
{
printf ("Usage: %s objectfile [newrpath]\n", argv[0]);
return 1;
}
if (argc == 2)
oflags = O_RDONLY;
else
oflags = O_RDWR;
fd = open(argv[1], oflags);
if (fd == -1)
{
perror ("open");
return 1;
}
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
{
perror ("reading header");
return 1;
}
if (*(unsigned *)ehdr.e_ident != *(const unsigned *)ELFMAG ||
ehdr.e_ident[EI_CLASS] != ELFCLASS32 ||
ehdr.e_ident[EI_DATA] != ELFDATA2LSB ||
ehdr.e_ident[EI_VERSION] != EV_CURRENT)
{
fprintf(stderr, "`%s' probably isn't a 32-bit LSB-first ELF file.\n",
argv[1]);
return 1;
}
if (ehdr.e_phentsize != sizeof(Elf32_Phdr))
{
fprintf(stderr, "section size was read as %d, not %d!\n",
ehdr.e_phentsize, sizeof(Elf32_Phdr));
return 1;
}
if (lseek(fd, ehdr.e_phoff, SEEK_SET) == -1)
{
perror ("positioning for sections");
return 1;
}
for (i = 0; i < ehdr.e_phnum; i++)
{
if (read(fd, &phdr, sizeof(phdr)) != sizeof(phdr))
{
perror ("reading section header");
return 1;
}
if (phdr.p_type == PT_DYNAMIC)
break;
}
if (i == ehdr.e_phnum)
{
fprintf (stderr, "No dynamic section found.\n");
return 2;
}
dyns = malloc(phdr.p_memsz);
if (dyns == NULL)
{
perror ("allocating memory for dynamic section");
return 1;
}
memset(dyns, 0, phdr.p_memsz);
if (lseek(fd, phdr.p_offset, SEEK_SET) == -1
|| read(fd, dyns, phdr.p_filesz) != phdr.p_filesz)
{
perror ("reading dynamic section");
return 1;
}
rpathoff = -1;
for (i = 0; dyns[i].d_tag != DT_NULL; i++)
{
if (dyns[i].d_tag == DT_RPATH)
{
rpathoff = dyns[i].d_un.d_ptr;
break;
}
}
if (rpathoff == -1)
{
fprintf (stderr, "No rpath tag found.\n");
return 2;
}
if (lseek(fd, ehdr.e_shoff, SEEK_SET) == -1)
{
perror ("positioning for sections");
return 1;
}
for (i = 0; i < ehdr.e_shnum; i++)
{
if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
{
perror ("reading section header");
return 1;
}
if (shdr.sh_type == SHT_STRTAB)
break;
}
if (i == ehdr.e_shnum)
{
fprintf (stderr, "No string table found.\n");
return 2;
}
strtab = (char *)malloc(shdr.sh_size);
if (strtab == NULL)
{
perror ("allocating memory for string table");
return 1;
}
memset(strtab, 0, shdr.sh_size);
if (lseek(fd, shdr.sh_offset, SEEK_SET) == -1)
{
perror ("positioning for string table");
return 1;
}
if (read(fd, strtab, shdr.sh_size) != shdr.sh_size)
{
perror ("reading string table");
return 1;
}
if (shdr.sh_size < rpathoff)
{
fprintf(stderr, "RPATH string offset not contained in string table");
return 5;
}
rpath = strtab+rpathoff;
printf("%s:existing RPATH: %s\n", argv[1], rpath);
if (argc == 2)
return 0;
rpathlen = strlen(rpath);
/*
* Calculate the maximum rpath length (will be equal to rpathlen unless
* we have previously truncated it).
*/
for ( i = rpathoff + rpathlen ; i < shdr.sh_size && strtab[i] == '\0' ; i++ );
i--;
if (i> rpathoff + rpathlen)
rpathlen = i - rpathoff;
if (strlen(argv[2]) > rpathlen)
{
fprintf(stderr, "new rpath '%s' too large; maximum length %i\n",
argv[2], rpathlen);
return 7;
}
memset(rpath, 0, rpathlen);
strcpy(rpath, argv[2]);
if (lseek(fd, shdr.sh_offset+rpathoff, SEEK_SET) == -1)
{
perror ("positioning for RPATH");
return 1;
}
if (write(fd, rpath, rpathlen) != rpathlen)
{
perror ("writing RPATH");
return 1;
}
printf("%s:new RPATH: %s\n", argv[1], rpath);
return 0;
}