0
|
1 /*
|
|
2 <URL:http://gcc.gnu.org/ml/gcc/1999-04n/msg01105.html>
|
|
3
|
|
4 Re: changing embedded RPATH in existing executables.
|
|
5
|
|
6 To: geoffk@ozemail.com.au
|
|
7 Subject: Re: changing embedded RPATH in existing executables.
|
|
8 From: <peeter_joot@VNET.IBM.COM> (peeter joot)
|
|
9 Date: Fri, 30 Apr 1999 16:14:44 -0400 (EDT)
|
|
10 Cc: peeterj@ca.ibm.com, egcs@cygnus.com, libc-hacker@cygnus.com, linux-gcc@vger.rutgers.edu
|
|
11 Reply-To: <peeter_joot@VNET.IBM.COM>
|
|
12
|
|
13 > _Changing_ is a little tricky, but the attached program strips rpaths
|
|
14 > from executables (I find it essential for debugging the binutils).
|
|
15 > It's endian-dependent, if you want this for x86 you can just change
|
|
16 > the occurrences of 'MSB' to 'LSB' and compile (I should really fix
|
|
17 > that).
|
|
18
|
|
19 Hi Geoff,
|
|
20
|
|
21 With your program as a guide (and some peeks into libbfd, elf.h, a bit
|
|
22 of the glibc dynamic loader code, objdump, and a hex-editor) I was able to
|
|
23 figure out enough to find and change the rpath string. That was fun!
|
|
24
|
|
25 This program assumes (unlike your original program) that there is only
|
|
26 one DT_RPATH tag in the dynamic section as even with multiple '-Wl,-rpath,'
|
|
27 commands in the link this seems to occur (they all get concatonated into
|
|
28 a : separated path).
|
|
29
|
|
30 Thanks for your help. If you want to use this on non-x86 you have to change
|
|
31 the occurances of LSB back to MSB:)
|
|
32
|
|
33 Peeter
|
|
34 --
|
|
35 */
|
|
36
|
|
37 #ifdef HAVE_CONFIG_H
|
|
38 # include "config.h"
|
|
39 #endif
|
|
40
|
|
41 #include <stdio.h>
|
|
42 #include <unistd.h>
|
|
43 #include <fcntl.h>
|
|
44 #include <elf.h>
|
|
45 #if defined(HAVE_LINK_H)
|
|
46 # include <link.h>
|
|
47 #endif /* HAVE_LINK_H */
|
|
48 #include <stdlib.h>
|
|
49 #include <string.h>
|
|
50 #include <sys/stat.h>
|
|
51 #include "protos.h"
|
|
52
|
|
53 /**
|
|
54 * Reads an ELF file, and reads or alters the RPATH setting.
|
|
55 *
|
|
56 * TODO:
|
|
57 * modify to add RPATH setting if none exists.
|
|
58 */
|
|
59
|
|
60
|
|
61 int
|
|
62 chrpath(const char *filename, const char *newpath, int convert)
|
|
63 {
|
|
64 int fd;
|
|
65 Elf_Ehdr ehdr;
|
|
66 int i;
|
|
67 Elf_Phdr phdr;
|
|
68 Elf_Shdr shdr;
|
|
69 Elf_Dyn *dyns;
|
|
70 int rpathoff;
|
|
71 char * strtab;
|
|
72 char * rpath;
|
|
73 unsigned int rpathlen;
|
|
74 int oflags;
|
|
75 int rpath_dyns_index;
|
|
76
|
|
77 if (NULL == newpath && 0 == convert)
|
|
78 oflags = O_RDONLY;
|
|
79 else
|
|
80 oflags = O_RDWR;
|
|
81
|
|
82 fd = elf_open(filename, oflags, &ehdr);
|
|
83 if (fd == -1)
|
|
84 {
|
|
85 perror ("elf_open");
|
|
86 return 1;
|
|
87 }
|
|
88
|
|
89 if (0 != elf_find_dynamic_section(fd, &ehdr, &phdr))
|
|
90 {
|
|
91 perror("found no dynamic section");
|
|
92 return 1;
|
|
93 }
|
|
94
|
|
95 dyns = malloc(phdr.p_filesz);
|
|
96 if (dyns == NULL)
|
|
97 {
|
|
98 perror ("allocating memory for dynamic section");
|
|
99 return 1;
|
|
100 }
|
|
101 memset(dyns, 0, phdr.p_filesz);
|
|
102 if (lseek(fd, phdr.p_offset, SEEK_SET) == -1
|
|
103 || read(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz)
|
|
104 {
|
|
105 perror ("reading dynamic section");
|
|
106 free(dyns);
|
|
107 return 1;
|
|
108 }
|
|
109
|
|
110 rpathoff = -1;
|
|
111 for ( rpath_dyns_index = 0; dyns[rpath_dyns_index].d_tag != DT_NULL;
|
|
112 ++rpath_dyns_index )
|
|
113 {
|
|
114 if ( elf_dynpath_tag(dyns[rpath_dyns_index].d_tag) )
|
|
115 {
|
|
116 rpathoff = dyns[rpath_dyns_index].d_un.d_ptr;
|
|
117 break;
|
|
118 }
|
|
119 }
|
|
120 if (rpathoff == -1)
|
|
121 {
|
|
122 printf("%s: no rpath or runpath tag found.\n", filename);
|
|
123 free(dyns);
|
|
124 return 2;
|
|
125 }
|
|
126
|
|
127 if (lseek(fd, ehdr.e_shoff, SEEK_SET) == -1)
|
|
128 {
|
|
129 perror ("positioning for sections");
|
|
130 free(dyns);
|
|
131 return 1;
|
|
132 }
|
|
133
|
|
134 for (i = 0; i < ehdr.e_shnum; i++)
|
|
135 {
|
|
136 if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
|
|
137 {
|
|
138 perror ("reading section header");
|
|
139 free(dyns);
|
|
140 return 1;
|
|
141 }
|
|
142 if (shdr.sh_type == SHT_STRTAB)
|
|
143 break;
|
|
144 }
|
|
145 if (i == ehdr.e_shnum)
|
|
146 {
|
|
147 fprintf (stderr, "No string table found.\n");
|
|
148 free(dyns);
|
|
149 return 2;
|
|
150 }
|
|
151 strtab = (char *)malloc(shdr.sh_size);
|
|
152 if (strtab == NULL)
|
|
153 {
|
|
154 perror ("allocating memory for string table");
|
|
155 free(dyns);
|
|
156 return 1;
|
|
157 }
|
|
158 memset(strtab, 0, shdr.sh_size);
|
|
159
|
|
160 if (lseek(fd, shdr.sh_offset, SEEK_SET) == -1)
|
|
161 {
|
|
162 perror ("positioning for string table");
|
|
163 free(strtab);
|
|
164 free(dyns);
|
|
165 return 1;
|
|
166 }
|
|
167 if (read(fd, strtab, shdr.sh_size) != (int)shdr.sh_size)
|
|
168 {
|
|
169 perror ("reading string table");
|
|
170 free(strtab);
|
|
171 free(dyns);
|
|
172 return 1;
|
|
173 }
|
|
174
|
|
175 if ((int)shdr.sh_size < rpathoff)
|
|
176 {
|
|
177 fprintf(stderr, "%s string offset not contained in string table",
|
|
178 elf_tagname(dyns[rpath_dyns_index].d_tag));
|
|
179 free(strtab);
|
|
180 free(dyns);
|
|
181 return 5;
|
|
182 }
|
|
183 rpath = strtab+rpathoff;
|
|
184
|
|
185 #if defined(DT_RUNPATH)
|
|
186 if (convert && dyns[rpath_dyns_index].d_tag == DT_RPATH)
|
|
187 {
|
|
188 dyns[rpath_dyns_index].d_tag = DT_RUNPATH;
|
|
189 if (lseek(fd, phdr.p_offset, SEEK_SET) == -1
|
|
190 || write(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz)
|
|
191 {
|
|
192 perror ("converting RPATH to RUNPATH");
|
|
193 return 1;
|
|
194 }
|
|
195 printf("%s: RPATH converted to RUNPATH\n", filename);
|
|
196 }
|
|
197 #endif /* DT_RUNPATH */
|
|
198
|
|
199 printf("%s: %s=%s\n", filename, elf_tagname(dyns[rpath_dyns_index].d_tag),
|
|
200 rpath);
|
|
201
|
|
202 if (NULL == newpath)
|
|
203 {
|
|
204 free(dyns);
|
|
205 free(strtab);
|
|
206 return 0;
|
|
207 }
|
|
208
|
|
209 rpathlen = strlen(rpath);
|
|
210
|
|
211 /*
|
|
212 * Calculate the maximum rpath length (will be equal to rpathlen unless
|
|
213 * we have previously truncated it).
|
|
214 */
|
|
215 for ( i = rpathoff + rpathlen ; (i < (int)shdr.sh_size
|
|
216 && strtab[i] == '\0') ; i++ )
|
|
217 ;
|
|
218 i--;
|
|
219
|
|
220 if (i > (int)(rpathoff + rpathlen))
|
|
221 rpathlen = i - rpathoff;
|
|
222
|
|
223 if (strlen(newpath) > rpathlen)
|
|
224 {
|
|
225 fprintf(stderr, "new rpath '%s' too large; maximum length %i\n",
|
|
226 newpath, rpathlen);
|
|
227 free(dyns);
|
|
228 free(strtab);
|
|
229 return 7;
|
|
230 }
|
|
231
|
|
232 memset(rpath, 0, rpathlen);
|
|
233 strcpy(rpath, newpath);
|
|
234
|
|
235 if (lseek(fd, shdr.sh_offset+rpathoff, SEEK_SET) == -1)
|
|
236 {
|
|
237 perror ("positioning for RPATH");
|
|
238 free(dyns);
|
|
239 free(strtab);
|
|
240 return 1;
|
|
241 }
|
|
242 if (write(fd, rpath, rpathlen) != (int)rpathlen)
|
|
243 {
|
|
244 perror ("writing RPATH");
|
|
245 free(dyns);
|
|
246 free(strtab);
|
|
247 return 1;
|
|
248 }
|
|
249 printf("%s: new %s: %s\n", filename,
|
|
250 elf_tagname(dyns[rpath_dyns_index].d_tag), rpath);
|
|
251
|
|
252 elf_close(fd);
|
|
253
|
|
254 free(dyns);
|
|
255 dyns = NULL;
|
|
256
|
|
257 free(strtab);
|
|
258
|
|
259 return 0;
|
|
260 }
|