1 #include <string>
2 #include <vector>
3 #include <set>
4 #include <map>
5 #include <algorithm>
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <assert.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <limits.h>
19
20 #include "elf.h"
21
22 using namespace std;
23
24
25 #ifdef MIPSEL
26 /* The lemote fuloong 2f kernel defconfig sets a page size of 16KB */
27 const unsigned int pageSize = 4096*4;
28 #else
29 const unsigned int pageSize = 4096;
30 #endif
31
32
33 static bool debugMode = false;
34
35 static bool forceRPath = false;
36
37 static string fileName;
38
39
40 off_t fileSize, maxSize;
41 unsigned char * contents = 0;
42
43
44 #define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym
45 #define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym
46
47
48 template<ElfFileParams>
49 class ElfFile
50 {
51 Elf_Ehdr * hdr;
52 vector<Elf_Phdr> phdrs;
53 vector<Elf_Shdr> shdrs;
54
55 bool littleEndian;
56
57 bool changed;
58
59 bool isExecutable;
60
61 typedef string SectionName;
62 typedef map<SectionName, string> ReplacedSections;
63
64 ReplacedSections replacedSections;
65
66 string sectionNames; /* content of the .shstrtab section */
67
68 /* Align on 4 or 8 bytes boundaries on 32- or 64-bit platforms
69 respectively. */
70 unsigned int sectionAlignment;
71
72 vector<SectionName> sectionsByOldIndex;
73
74 public:
75
ElfFile()76 ElfFile()
77 {
78 changed = false;
79 sectionAlignment = sizeof(Elf_Off);
80 }
81
isChanged()82 bool isChanged()
83 {
84 return changed;
85 }
86
87 void parse();
88
89 private:
90
91 struct CompPhdr
92 {
93 ElfFile * elfFile;
operator ()ElfFile::CompPhdr94 bool operator ()(const Elf_Phdr & x, const Elf_Phdr & y)
95 {
96 if (x.p_type == PT_PHDR) return true;
97 if (y.p_type == PT_PHDR) return false;
98 return elfFile->rdi(x.p_paddr) < elfFile->rdi(y.p_paddr);
99 }
100 };
101
102 friend struct CompPhdr;
103
104 void sortPhdrs();
105
106 struct CompShdr
107 {
108 ElfFile * elfFile;
operator ()ElfFile::CompShdr109 bool operator ()(const Elf_Shdr & x, const Elf_Shdr & y)
110 {
111 return elfFile->rdi(x.sh_offset) < elfFile->rdi(y.sh_offset);
112 }
113 };
114
115 friend struct CompShdr;
116
117 void sortShdrs();
118
119 void shiftFile(unsigned int extraPages, Elf_Addr startPage);
120
121 string getSectionName(const Elf_Shdr & shdr);
122
123 Elf_Shdr & findSection(const SectionName & sectionName);
124
125 Elf_Shdr * findSection2(const SectionName & sectionName);
126
127 unsigned int findSection3(const SectionName & sectionName);
128
129 string & replaceSection(const SectionName & sectionName,
130 unsigned int size);
131
132 void writeReplacedSections(Elf_Off & curOff,
133 Elf_Addr startAddr, Elf_Off startOffset);
134
135 void rewriteHeaders(Elf_Addr phdrAddress);
136
137 void rewriteSectionsLibrary();
138
139 void rewriteSectionsExecutable();
140
141 public:
142
143 void rewriteSections();
144
145 string getInterpreter();
146
147 void setInterpreter(const string & newInterpreter);
148
149 typedef enum { rpPrint, rpShrink, rpSet } RPathOp;
150
151 void modifyRPath(RPathOp op, string newRPath);
152
153 void removeNeeded(set<string> libs);
154
155 private:
156
157 /* Convert an integer in big or little endian representation (as
158 specified by the ELF header) to this platform's integer
159 representation. */
160 template<class I>
161 I rdi(I i);
162
163 /* Convert back to the ELF representation. */
164 template<class I>
wri(I & t,unsigned long long i)165 I wri(I & t, unsigned long long i)
166 {
167 t = rdi((I) i);
168 return i;
169 }
170 };
171
172
173 /* !!! G++ creates broken code if this function is inlined, don't know
174 why... */
175 template<ElfFileParams>
176 template<class I>
rdi(I i)177 I ElfFile<ElfFileParamNames>::rdi(I i)
178 {
179 I r = 0;
180 if (littleEndian) {
181 for (unsigned int n = 0; n < sizeof(I); ++n) {
182 r |= ((I) *(((unsigned char *) &i) + n)) << (n * 8);
183 }
184 } else {
185 for (unsigned int n = 0; n < sizeof(I); ++n) {
186 r |= ((I) *(((unsigned char *) &i) + n)) << ((sizeof(I) - n - 1) * 8);
187 }
188 }
189 return r;
190 }
191
192
193 /* Ugly: used to erase DT_RUNPATH when using --force-rpath. */
194 #define DT_IGNORE 0x00726e67
195
196
debug(const char * format,...)197 static void debug(const char * format, ...)
198 {
199 if (debugMode) {
200 va_list ap;
201 va_start(ap, format);
202 vfprintf(stderr, format, ap);
203 va_end(ap);
204 }
205 }
206
207
error(string msg)208 static void error(string msg)
209 {
210 if (errno) perror(msg.c_str()); else fprintf(stderr, "%s\n", msg.c_str());
211 exit(1);
212 }
213
214
growFile(off_t newSize)215 static void growFile(off_t newSize)
216 {
217 if (newSize > maxSize) error("maximum file size exceeded");
218 if (newSize <= fileSize) return;
219 if (newSize > fileSize)
220 memset(contents + fileSize, 0, newSize - fileSize);
221 fileSize = newSize;
222 }
223
224
readFile(string fileName,mode_t * fileMode)225 static void readFile(string fileName, mode_t * fileMode)
226 {
227 struct stat st;
228 if (stat(fileName.c_str(), &st) != 0) error("stat");
229 fileSize = st.st_size;
230 *fileMode = st.st_mode;
231 maxSize = fileSize + 8 * 1024 * 1024;
232
233 contents = (unsigned char *) malloc(fileSize + maxSize);
234 if (!contents) abort();
235
236 int fd = open(fileName.c_str(), O_RDONLY);
237 if (fd == -1) error("open");
238
239 if (read(fd, contents, fileSize) != fileSize) error("read");
240
241 close(fd);
242 }
243
244
checkPointer(void * p,unsigned int size)245 static void checkPointer(void * p, unsigned int size)
246 {
247 unsigned char * q = (unsigned char *) p;
248 assert(q >= contents && q + size <= contents + fileSize);
249 }
250
251
252 template<ElfFileParams>
parse()253 void ElfFile<ElfFileParamNames>::parse()
254 {
255 isExecutable = false;
256
257 /* Check the ELF header for basic validity. */
258 if (fileSize < (off_t) sizeof(Elf_Ehdr)) error("missing ELF header");
259
260 hdr = (Elf_Ehdr *) contents;
261
262 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0)
263 error("not an ELF executable");
264
265 littleEndian = contents[EI_DATA] == ELFDATA2LSB;
266
267 if (rdi(hdr->e_type) != ET_EXEC && rdi(hdr->e_type) != ET_DYN)
268 error("wrong ELF type");
269
270 if ((off_t) (rdi(hdr->e_phoff) + rdi(hdr->e_phnum) * rdi(hdr->e_phentsize)) > fileSize)
271 error("missing program headers");
272
273 if ((off_t) (rdi(hdr->e_shoff) + rdi(hdr->e_shnum) * rdi(hdr->e_shentsize)) > fileSize)
274 error("missing section headers");
275
276 if (rdi(hdr->e_phentsize) != sizeof(Elf_Phdr))
277 error("program headers have wrong size");
278
279 /* Copy the program and section headers. */
280 for (int i = 0; i < rdi(hdr->e_phnum); ++i) {
281 phdrs.push_back(* ((Elf_Phdr *) (contents + rdi(hdr->e_phoff)) + i));
282 if (rdi(phdrs[i].p_type) == PT_INTERP) isExecutable = true;
283 }
284
285 for (int i = 0; i < rdi(hdr->e_shnum); ++i)
286 shdrs.push_back(* ((Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i));
287
288 /* Get the section header string table section (".shstrtab"). Its
289 index in the section header table is given by e_shstrndx field
290 of the ELF header. */
291 unsigned int shstrtabIndex = rdi(hdr->e_shstrndx);
292 assert(shstrtabIndex < shdrs.size());
293 unsigned int shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size);
294 char * shstrtab = (char * ) contents + rdi(shdrs[shstrtabIndex].sh_offset);
295 checkPointer(shstrtab, shstrtabSize);
296
297 assert(shstrtabSize > 0);
298 assert(shstrtab[shstrtabSize - 1] == 0);
299
300 sectionNames = string(shstrtab, shstrtabSize);
301
302 sectionsByOldIndex.resize(hdr->e_shnum);
303 for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
304 sectionsByOldIndex[i] = getSectionName(shdrs[i]);
305 }
306
307
308 template<ElfFileParams>
sortPhdrs()309 void ElfFile<ElfFileParamNames>::sortPhdrs()
310 {
311 /* Sort the segments by offset. */
312 CompPhdr comp;
313 comp.elfFile = this;
314 sort(phdrs.begin(), phdrs.end(), comp);
315 }
316
317
318 template<ElfFileParams>
sortShdrs()319 void ElfFile<ElfFileParamNames>::sortShdrs()
320 {
321 /* Translate sh_link mappings to section names, since sorting the
322 sections will invalidate the sh_link fields. */
323 map<SectionName, SectionName> linkage;
324 for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
325 if (rdi(shdrs[i].sh_link) != 0)
326 linkage[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_link)]);
327
328 /* Idem for sh_info on certain sections. */
329 map<SectionName, SectionName> info;
330 for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
331 if (rdi(shdrs[i].sh_info) != 0 &&
332 (rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA))
333 info[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_info)]);
334
335 /* Idem for the index of the .shstrtab section in the ELF header. */
336 SectionName shstrtabName = getSectionName(shdrs[rdi(hdr->e_shstrndx)]);
337
338 /* Sort the sections by offset. */
339 CompShdr comp;
340 comp.elfFile = this;
341 sort(shdrs.begin(), shdrs.end(), comp);
342
343 /* Restore the sh_link mappings. */
344 for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
345 if (rdi(shdrs[i].sh_link) != 0)
346 wri(shdrs[i].sh_link,
347 findSection3(linkage[getSectionName(shdrs[i])]));
348
349 /* And the st_info mappings. */
350 for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
351 if (rdi(shdrs[i].sh_info) != 0 &&
352 (rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA))
353 wri(shdrs[i].sh_info,
354 findSection3(info[getSectionName(shdrs[i])]));
355
356 /* And the .shstrtab index. */
357 wri(hdr->e_shstrndx, findSection3(shstrtabName));
358 }
359
360
writeFile(string fileName,mode_t fileMode)361 static void writeFile(string fileName, mode_t fileMode)
362 {
363 string fileName2 = fileName + "_patchelf_tmp";
364
365 int fd = open(fileName2.c_str(),
366 O_CREAT | O_TRUNC | O_WRONLY, 0700);
367 if (fd == -1) error("open");
368
369 if (write(fd, contents, fileSize) != fileSize) error("write");
370
371 if (close(fd) != 0) error("close");
372
373 if (chmod(fileName2.c_str(), fileMode) != 0) error("chmod");
374
375 if (rename(fileName2.c_str(), fileName.c_str()) != 0) error("rename");
376 }
377
378
roundUp(unsigned int n,unsigned int m)379 static unsigned int roundUp(unsigned int n, unsigned int m)
380 {
381 return ((n - 1) / m + 1) * m;
382 }
383
384
385 template<ElfFileParams>
shiftFile(unsigned int extraPages,Elf_Addr startPage)386 void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, Elf_Addr startPage)
387 {
388 /* Move the entire contents of the file `extraPages' pages
389 further. */
390 unsigned int oldSize = fileSize;
391 unsigned int shift = extraPages * pageSize;
392 growFile(fileSize + extraPages * pageSize);
393 memmove(contents + extraPages * pageSize, contents, oldSize);
394 memset(contents + sizeof(Elf_Ehdr), 0, shift - sizeof(Elf_Ehdr));
395
396 /* Adjust the ELF header. */
397 wri(hdr->e_phoff, sizeof(Elf_Ehdr));
398 wri(hdr->e_shoff, rdi(hdr->e_shoff) + shift);
399
400 /* Update the offsets in the section headers. */
401 for (int i = 1; i < rdi(hdr->e_shnum); ++i)
402 wri(shdrs[i].sh_offset, rdi(shdrs[i].sh_offset) + shift);
403
404 /* Update the offsets in the program headers. */
405 for (int i = 0; i < rdi(hdr->e_phnum); ++i) {
406 wri(phdrs[i].p_offset, rdi(phdrs[i].p_offset) + shift);
407 if (rdi(phdrs[i].p_align) != 0 &&
408 (rdi(phdrs[i].p_vaddr) - rdi(phdrs[i].p_offset)) % rdi(phdrs[i].p_align) != 0) {
409 debug("changing alignment of program header %d from %d to %d\n", i,
410 rdi(phdrs[i].p_align), pageSize);
411 wri(phdrs[i].p_align, pageSize);
412 }
413 }
414
415 /* Add a segment that maps the new program/section headers and
416 PT_INTERP segment into memory. Otherwise glibc will choke. */
417 phdrs.resize(rdi(hdr->e_phnum) + 1);
418 wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1);
419 Elf_Phdr & phdr = phdrs[rdi(hdr->e_phnum) - 1];
420 wri(phdr.p_type, PT_LOAD);
421 wri(phdr.p_offset, 0);
422 wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
423 wri(phdr.p_filesz, wri(phdr.p_memsz, shift));
424 wri(phdr.p_flags, PF_R | PF_W);
425 wri(phdr.p_align, pageSize);
426 }
427
428
429 template<ElfFileParams>
getSectionName(const Elf_Shdr & shdr)430 string ElfFile<ElfFileParamNames>::getSectionName(const Elf_Shdr & shdr)
431 {
432 return string(sectionNames.c_str() + rdi(shdr.sh_name));
433 }
434
435
436 template<ElfFileParams>
findSection(const SectionName & sectionName)437 Elf_Shdr & ElfFile<ElfFileParamNames>::findSection(const SectionName & sectionName)
438 {
439 Elf_Shdr * shdr = findSection2(sectionName);
440 if (!shdr)
441 error("cannot find section " + sectionName);
442 return *shdr;
443 }
444
445
446 template<ElfFileParams>
findSection2(const SectionName & sectionName)447 Elf_Shdr * ElfFile<ElfFileParamNames>::findSection2(const SectionName & sectionName)
448 {
449 unsigned int i = findSection3(sectionName);
450 return i ? &shdrs[i] : 0;
451 }
452
453
454 template<ElfFileParams>
findSection3(const SectionName & sectionName)455 unsigned int ElfFile<ElfFileParamNames>::findSection3(const SectionName & sectionName)
456 {
457 for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
458 if (getSectionName(shdrs[i]) == sectionName) return i;
459 return 0;
460 }
461
462
463 template<ElfFileParams>
replaceSection(const SectionName & sectionName,unsigned int size)464 string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sectionName,
465 unsigned int size)
466 {
467 ReplacedSections::iterator i = replacedSections.find(sectionName);
468 string s;
469
470 if (i != replacedSections.end()) {
471 s = string(i->second);
472 } else {
473 Elf_Shdr & shdr = findSection(sectionName);
474 s = string((char *) contents + rdi(shdr.sh_offset), rdi(shdr.sh_size));
475 }
476
477 s.resize(size);
478 replacedSections[sectionName] = s;
479
480 return replacedSections[sectionName];
481 }
482
483
484 template<ElfFileParams>
writeReplacedSections(Elf_Off & curOff,Elf_Addr startAddr,Elf_Off startOffset)485 void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
486 Elf_Addr startAddr, Elf_Off startOffset)
487 {
488 /* Overwrite the old section contents with 'X's. Do this
489 *before* writing the new section contents (below) to prevent
490 clobbering previously written new section contents. */
491 for (ReplacedSections::iterator i = replacedSections.begin();
492 i != replacedSections.end(); ++i)
493 {
494 string sectionName = i->first;
495 Elf_Shdr & shdr = findSection(sectionName);
496 memset(contents + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size));
497 }
498
499 for (ReplacedSections::iterator i = replacedSections.begin();
500 i != replacedSections.end(); ++i)
501 {
502 string sectionName = i->first;
503 Elf_Shdr & shdr = findSection(sectionName);
504 debug("rewriting section `%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n",
505 sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i->second.size());
506
507 memcpy(contents + curOff, (unsigned char *) i->second.c_str(),
508 i->second.size());
509
510 /* Update the section header for this section. */
511 wri(shdr.sh_offset, curOff);
512 wri(shdr.sh_addr, startAddr + (curOff - startOffset));
513 wri(shdr.sh_size, i->second.size());
514 wri(shdr.sh_addralign, sectionAlignment);
515
516 /* If this is the .interp section, then the PT_INTERP segment
517 must be sync'ed with it. */
518 if (sectionName == ".interp") {
519 for (unsigned int j = 0; j < phdrs.size(); ++j)
520 if (rdi(phdrs[j].p_type) == PT_INTERP) {
521 phdrs[j].p_offset = shdr.sh_offset;
522 phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr;
523 phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size;
524 }
525 }
526
527 /* If this is the .dynamic section, then the PT_DYNAMIC segment
528 must be sync'ed with it. */
529 if (sectionName == ".dynamic") {
530 for (unsigned int j = 0; j < phdrs.size(); ++j)
531 if (rdi(phdrs[j].p_type) == PT_DYNAMIC) {
532 phdrs[j].p_offset = shdr.sh_offset;
533 phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr;
534 phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size;
535 }
536 }
537
538 curOff += roundUp(i->second.size(), sectionAlignment);
539 }
540
541 replacedSections.clear();
542 }
543
544
545 template<ElfFileParams>
rewriteSectionsLibrary()546 void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
547 {
548 /* For dynamic libraries, we just place the replacement sections
549 at the end of the file. They're mapped into memory by a
550 PT_LOAD segment located directly after the last virtual address
551 page of other segments. */
552 Elf_Addr startPage = 0;
553 for (unsigned int i = 0; i < phdrs.size(); ++i) {
554 Elf_Addr thisPage = roundUp(rdi(phdrs[i].p_vaddr) + rdi(phdrs[i].p_memsz), pageSize);
555 if (thisPage > startPage) startPage = thisPage;
556 }
557
558 debug("last page is 0x%llx\n", (unsigned long long) startPage);
559
560
561 /* Compute the total space needed for the replaced sections and
562 the program headers. */
563 off_t neededSpace = (phdrs.size() + 1) * sizeof(Elf_Phdr);
564 for (ReplacedSections::iterator i = replacedSections.begin();
565 i != replacedSections.end(); ++i)
566 neededSpace += roundUp(i->second.size(), sectionAlignment);
567 debug("needed space is %d\n", neededSpace);
568
569
570 size_t startOffset = roundUp(fileSize, pageSize);
571
572 growFile(startOffset + neededSpace);
573
574
575 /* Even though this file is of type ET_DYN, it could actually be
576 an executable. For instance, Gold produces executables marked
577 ET_DYN. In that case we can still hit the kernel bug that
578 necessitated rewriteSectionsExecutable(). However, such
579 executables also tend to start at virtual address 0, so
580 rewriteSectionsExecutable() won't work because it doesn't have
581 any virtual address space to grow downwards into. As a
582 workaround, make sure that the virtual address of our new
583 PT_LOAD segment relative to the first PT_LOAD segment is equal
584 to its offset; otherwise we hit the kernel bug. This may
585 require creating a hole in the executable. The bigger the size
586 of the uninitialised data segment, the bigger the hole. */
587 if (isExecutable) {
588 if (startOffset >= startPage) {
589 debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage);
590 } else {
591 size_t hole = startPage - startOffset;
592 /* Print a warning, because the hole could be very big. */
593 fprintf(stderr, "warning: working around a Linux kernel bug by creating a hole of %zu bytes in ‘%s’\n", hole, fileName.c_str());
594 assert(hole % pageSize == 0);
595 /* !!! We could create an actual hole in the file here,
596 but it's probably not worth the effort. */
597 growFile(fileSize + hole);
598 startOffset += hole;
599 }
600 startPage = startOffset;
601 }
602
603
604 /* Add a segment that maps the replaced sections and program
605 headers into memory. */
606 phdrs.resize(rdi(hdr->e_phnum) + 1);
607 wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1);
608 Elf_Phdr & phdr = phdrs[rdi(hdr->e_phnum) - 1];
609 wri(phdr.p_type, PT_LOAD);
610 wri(phdr.p_offset, startOffset);
611 wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
612 wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace));
613 wri(phdr.p_flags, PF_R | PF_W);
614 wri(phdr.p_align, pageSize);
615
616
617 /* Write out the replaced sections. */
618 Elf_Off curOff = startOffset + phdrs.size() * sizeof(Elf_Phdr);
619 writeReplacedSections(curOff, startPage, startOffset);
620 assert((off_t) curOff == startOffset + neededSpace);
621
622
623 /* Move the program header to the start of the new area. */
624 wri(hdr->e_phoff, startOffset);
625
626 rewriteHeaders(startPage);
627 }
628
629
630 template<ElfFileParams>
rewriteSectionsExecutable()631 void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
632 {
633 /* Sort the sections by offset, otherwise we won't correctly find
634 all the sections before the last replaced section. */
635 sortShdrs();
636
637
638 /* What is the index of the last replaced section? */
639 unsigned int lastReplaced = 0;
640 for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) {
641 string sectionName = getSectionName(shdrs[i]);
642 if (replacedSections.find(sectionName) != replacedSections.end()) {
643 debug("using replaced section `%s'\n", sectionName.c_str());
644 lastReplaced = i;
645 }
646 }
647
648 assert(lastReplaced != 0);
649
650 debug("last replaced is %d\n", lastReplaced);
651
652 /* Try to replace all sections before that, as far as possible.
653 Stop when we reach an irreplacable section (such as one of type
654 SHT_PROGBITS). These cannot be moved in virtual address space
655 since that would invalidate absolute references to them. */
656 assert(lastReplaced + 1 < shdrs.size()); /* !!! I'm lazy. */
657 size_t startOffset = rdi(shdrs[lastReplaced + 1].sh_offset);
658 Elf_Addr startAddr = rdi(shdrs[lastReplaced + 1].sh_addr);
659 string prevSection;
660 for (unsigned int i = 1; i <= lastReplaced; ++i) {
661 Elf_Shdr & shdr(shdrs[i]);
662 string sectionName = getSectionName(shdr);
663 debug("looking at section `%s'\n", sectionName.c_str());
664 /* !!! Why do we stop after a .dynstr section? I can't
665 remember! */
666 if ((rdi(shdr.sh_type) == SHT_PROGBITS && sectionName != ".interp")
667 || prevSection == ".dynstr")
668 {
669 startOffset = rdi(shdr.sh_offset);
670 startAddr = rdi(shdr.sh_addr);
671 lastReplaced = i - 1;
672 break;
673 } else {
674 if (replacedSections.find(sectionName) == replacedSections.end()) {
675 debug("replacing section `%s' which is in the way\n", sectionName.c_str());
676 replaceSection(sectionName, rdi(shdr.sh_size));
677 }
678 }
679 prevSection = sectionName;
680 }
681
682 debug("first reserved offset/addr is 0x%x/0x%llx\n",
683 startOffset, (unsigned long long) startAddr);
684
685 assert(startAddr % pageSize == startOffset % pageSize);
686 Elf_Addr firstPage = startAddr - startOffset;
687 debug("first page is 0x%llx\n", (unsigned long long) firstPage);
688
689 /* Right now we assume that the section headers are somewhere near
690 the end, which appears to be the case most of the time.
691 Therefore they're not accidentally overwritten by the replaced
692 sections. !!! Fix this. */
693 assert((off_t) rdi(hdr->e_shoff) >= startOffset);
694
695
696 /* Compute the total space needed for the replaced sections, the
697 ELF header, and the program headers. */
698 size_t neededSpace = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr);
699 for (ReplacedSections::iterator i = replacedSections.begin();
700 i != replacedSections.end(); ++i)
701 neededSpace += roundUp(i->second.size(), sectionAlignment);
702
703 debug("needed space is %d\n", neededSpace);
704
705 /* If we need more space at the start of the file, then grow the
706 file by the minimum number of pages and adjust internal
707 offsets. */
708 if (neededSpace > startOffset) {
709
710 /* We also need an additional program header, so adjust for that. */
711 neededSpace += sizeof(Elf_Phdr);
712 debug("needed space is %d\n", neededSpace);
713
714 unsigned int neededPages = roundUp(neededSpace - startOffset, pageSize) / pageSize;
715 debug("needed pages is %d\n", neededPages);
716 if (neededPages * pageSize > firstPage)
717 error("virtual address space underrun!");
718
719 firstPage -= neededPages * pageSize;
720 startOffset += neededPages * pageSize;
721
722 shiftFile(neededPages, firstPage);
723 }
724
725
726 /* Clear out the free space. */
727 Elf_Off curOff = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr);
728 debug("clearing first %d bytes\n", startOffset - curOff);
729 memset(contents + curOff, 0, startOffset - curOff);
730
731
732 /* Write out the replaced sections. */
733 writeReplacedSections(curOff, firstPage, 0);
734 assert((off_t) curOff == neededSpace);
735
736
737 rewriteHeaders(firstPage + rdi(hdr->e_phoff));
738 }
739
740
741 template<ElfFileParams>
rewriteSections()742 void ElfFile<ElfFileParamNames>::rewriteSections()
743 {
744 if (replacedSections.empty()) return;
745
746 for (ReplacedSections::iterator i = replacedSections.begin();
747 i != replacedSections.end(); ++i)
748 debug("replacing section `%s' with size %d\n",
749 i->first.c_str(), i->second.size());
750
751 if (rdi(hdr->e_type) == ET_DYN) {
752 debug("this is a dynamic library\n");
753 rewriteSectionsLibrary();
754 } else if (rdi(hdr->e_type) == ET_EXEC) {
755 debug("this is an executable\n");
756 rewriteSectionsExecutable();
757 } else error("unknown ELF type");
758 }
759
760
761 template<ElfFileParams>
rewriteHeaders(Elf_Addr phdrAddress)762 void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
763 {
764 /* Rewrite the program header table. */
765
766 /* If there is a segment for the program header table, update it.
767 (According to the ELF spec, it must be the first entry.) */
768 if (rdi(phdrs[0].p_type) == PT_PHDR) {
769 phdrs[0].p_offset = hdr->e_phoff;
770 wri(phdrs[0].p_vaddr, wri(phdrs[0].p_paddr, phdrAddress));
771 wri(phdrs[0].p_filesz, wri(phdrs[0].p_memsz, phdrs.size() * sizeof(Elf_Phdr)));
772 }
773
774 sortPhdrs();
775
776 for (unsigned int i = 0; i < phdrs.size(); ++i)
777 * ((Elf_Phdr *) (contents + rdi(hdr->e_phoff)) + i) = phdrs[i];
778
779
780 /* Rewrite the section header table. For neatness, keep the
781 sections sorted. */
782 assert(rdi(hdr->e_shnum) == shdrs.size());
783 sortShdrs();
784 for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
785 * ((Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i) = shdrs[i];
786
787
788 /* Update all those nasty virtual addresses in the .dynamic
789 section. Note that not all executables have .dynamic sections
790 (e.g., those produced by klibc's klcc). */
791 Elf_Shdr * shdrDynamic = findSection2(".dynamic");
792 if (shdrDynamic) {
793 Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic->sh_offset));
794 unsigned int d_tag;
795 for ( ; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++)
796 if (d_tag == DT_STRTAB)
797 dyn->d_un.d_ptr = findSection(".dynstr").sh_addr;
798 else if (d_tag == DT_STRSZ)
799 dyn->d_un.d_val = findSection(".dynstr").sh_size;
800 else if (d_tag == DT_SYMTAB)
801 dyn->d_un.d_ptr = findSection(".dynsym").sh_addr;
802 else if (d_tag == DT_HASH)
803 dyn->d_un.d_ptr = findSection(".hash").sh_addr;
804 else if (d_tag == DT_GNU_HASH)
805 dyn->d_un.d_ptr = findSection(".gnu.hash").sh_addr;
806 else if (d_tag == DT_JMPREL) {
807 Elf_Shdr * shdr = findSection2(".rel.plt");
808 if (!shdr) shdr = findSection2(".rela.plt"); /* 64-bit Linux, x86-64 */
809 if (!shdr) shdr = findSection2(".rela.IA_64.pltoff"); /* 64-bit Linux, IA-64 */
810 if (!shdr) error("cannot find section corresponding to DT_JMPREL");
811 dyn->d_un.d_ptr = shdr->sh_addr;
812 }
813 else if (d_tag == DT_REL) { /* !!! hack! */
814 Elf_Shdr * shdr = findSection2(".rel.dyn");
815 /* no idea if this makes sense, but it was needed for some
816 program */
817 if (!shdr) shdr = findSection2(".rel.got");
818 if (!shdr) error("cannot find .rel.dyn or .rel.got");
819 dyn->d_un.d_ptr = shdr->sh_addr;
820 }
821 else if (d_tag == DT_RELA)
822 dyn->d_un.d_ptr = findSection(".rela.dyn").sh_addr; /* PPC Linux */
823 else if (d_tag == DT_VERNEED)
824 dyn->d_un.d_ptr = findSection(".gnu.version_r").sh_addr;
825 else if (d_tag == DT_VERSYM)
826 dyn->d_un.d_ptr = findSection(".gnu.version").sh_addr;
827 }
828
829
830 /* Rewrite the .dynsym section. It contains the indices of the
831 sections in which symbols appear, so these need to be
832 remapped. */
833 for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) {
834 if (rdi(shdrs[i].sh_type) != SHT_SYMTAB && rdi(shdrs[i].sh_type) != SHT_DYNSYM) continue;
835 debug("rewriting symbol table section %d\n", i);
836 for (size_t entry = 0; (entry + 1) * sizeof(Elf_Sym) <= rdi(shdrs[i].sh_size); entry++) {
837 Elf_Sym * sym = (Elf_Sym *) (contents + rdi(shdrs[i].sh_offset) + entry * sizeof(Elf_Sym));
838 if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) {
839 string section = sectionsByOldIndex[rdi(sym->st_shndx)];
840 assert(!section.empty());
841 unsigned int newIndex = findSection3(section); // inefficient
842 //debug("rewriting symbol %d: index = %d (%s) -> %d\n", entry, rdi(sym->st_shndx), section.c_str(), newIndex);
843 wri(sym->st_shndx, newIndex);
844 }
845 }
846 }
847 }
848
849
850
setSubstr(string & s,unsigned int pos,const string & t)851 static void setSubstr(string & s, unsigned int pos, const string & t)
852 {
853 assert(pos + t.size() <= s.size());
854 copy(t.begin(), t.end(), s.begin() + pos);
855 }
856
857
858 template<ElfFileParams>
getInterpreter()859 string ElfFile<ElfFileParamNames>::getInterpreter()
860 {
861 Elf_Shdr & shdr = findSection(".interp");
862 return string((char *) contents + rdi(shdr.sh_offset), rdi(shdr.sh_size));
863 }
864
865
866 template<ElfFileParams>
setInterpreter(const string & newInterpreter)867 void ElfFile<ElfFileParamNames>::setInterpreter(const string & newInterpreter)
868 {
869 string & section = replaceSection(".interp", newInterpreter.size() + 1);
870 setSubstr(section, 0, newInterpreter + '\0');
871 changed = true;
872 }
873
874
concatToRPath(string & rpath,const string & path)875 static void concatToRPath(string & rpath, const string & path)
876 {
877 if (!rpath.empty()) rpath += ":";
878 rpath += path;
879 }
880
881
882 template<ElfFileParams>
modifyRPath(RPathOp op,string newRPath)883 void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
884 {
885 Elf_Shdr & shdrDynamic = findSection(".dynamic");
886
887 /* !!! We assume that the virtual address in the DT_STRTAB entry
888 of the dynamic section corresponds to the .dynstr section. */
889 Elf_Shdr & shdrDynStr = findSection(".dynstr");
890 char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset);
891
892 /* Find the DT_STRTAB entry in the dynamic section. */
893 Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset));
894 Elf_Addr strTabAddr = 0;
895 for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++)
896 if (rdi(dyn->d_tag) == DT_STRTAB) strTabAddr = rdi(dyn->d_un.d_ptr);
897 if (!strTabAddr) error("strange: no string table");
898
899 assert(strTabAddr == rdi(shdrDynStr.sh_addr));
900
901
902 /* Walk through the dynamic section, look for the RPATH/RUNPATH
903 entry.
904
905 According to the ld.so docs, DT_RPATH is obsolete, we should
906 use DT_RUNPATH. DT_RUNPATH has two advantages: it can be
907 overriden by LD_LIBRARY_PATH, and it's scoped (the DT_RUNPATH
908 for an executable or library doesn't affect the search path for
909 libraries used by it). DT_RPATH is ignored if DT_RUNPATH is
910 present. The binutils `ld' still generates only DT_RPATH,
911 unless you use its `--enable-new-dtag' option, in which case it
912 generates a DT_RPATH and DT_RUNPATH pointing at the same
913 string. */
914 static vector<string> neededLibs;
915 dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset));
916 Elf_Dyn * dynRPath = 0, * dynRunPath = 0;
917 char * rpath = 0;
918 for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
919 if (rdi(dyn->d_tag) == DT_RPATH) {
920 dynRPath = dyn;
921 /* Only use DT_RPATH if there is no DT_RUNPATH. */
922 if (!dynRunPath)
923 rpath = strTab + rdi(dyn->d_un.d_val);
924 }
925 else if (rdi(dyn->d_tag) == DT_RUNPATH) {
926 dynRunPath = dyn;
927 rpath = strTab + rdi(dyn->d_un.d_val);
928 }
929 else if (rdi(dyn->d_tag) == DT_NEEDED)
930 neededLibs.push_back(string(strTab + rdi(dyn->d_un.d_val)));
931 }
932
933 if (op == rpPrint) {
934 printf("%s\n", rpath ? rpath : "");
935 return;
936 }
937
938 if (op == rpShrink && !rpath) {
939 debug("no RPATH to shrink\n");
940 return;
941 }
942
943
944 /* For each directory in the RPATH, check if it contains any
945 needed library. */
946 if (op == rpShrink) {
947 static vector<bool> neededLibFound(neededLibs.size(), false);
948
949 newRPath = "";
950
951 char * pos = rpath;
952 while (*pos) {
953 char * end = strchr(pos, ':');
954 if (!end) end = strchr(pos, 0);
955
956 /* Get the name of the directory. */
957 string dirName(pos, end - pos);
958 if (*end == ':') ++end;
959 pos = end;
960
961 /* Non-absolute entries are allowed (e.g., the special
962 "$ORIGIN" hack). */
963 if (dirName[0] != '/') {
964 concatToRPath(newRPath, dirName);
965 continue;
966 }
967
968 /* For each library that we haven't found yet, see if it
969 exists in this directory. */
970 bool libFound = false;
971 for (unsigned int j = 0; j < neededLibs.size(); ++j)
972 if (!neededLibFound[j]) {
973 string libName = dirName + "/" + neededLibs[j];
974 struct stat st;
975 if (stat(libName.c_str(), &st) == 0) {
976 neededLibFound[j] = true;
977 libFound = true;
978 }
979 }
980
981 if (!libFound)
982 debug("removing directory `%s' from RPATH\n", dirName.c_str());
983 else
984 concatToRPath(newRPath, dirName);
985 }
986 }
987
988
989 if (string(rpath ? rpath : "") == newRPath) return;
990
991 changed = true;
992
993 /* Zero out the previous rpath to prevent retained dependencies in
994 Nix. */
995 unsigned int rpathSize = 0;
996 if (rpath) {
997 rpathSize = strlen(rpath);
998 memset(rpath, 'X', rpathSize);
999 }
1000
1001 debug("new rpath is `%s'\n", newRPath.c_str());
1002
1003 if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */
1004 dynRPath->d_tag = DT_RUNPATH;
1005 dynRunPath = dynRPath;
1006 dynRPath = 0;
1007 }
1008
1009 if (forceRPath && dynRPath && dynRunPath) { /* convert DT_RUNPATH to DT_RPATH */
1010 dynRunPath->d_tag = DT_IGNORE;
1011 }
1012
1013 if (newRPath.size() <= rpathSize) {
1014 strcpy(rpath, newRPath.c_str());
1015 return;
1016 }
1017
1018 /* Grow the .dynstr section to make room for the new RPATH. */
1019 debug("rpath is too long, resizing...\n");
1020
1021 string & newDynStr = replaceSection(".dynstr",
1022 rdi(shdrDynStr.sh_size) + newRPath.size() + 1);
1023 setSubstr(newDynStr, rdi(shdrDynStr.sh_size), newRPath + '\0');
1024
1025 /* Update the DT_RUNPATH and DT_RPATH entries. */
1026 if (dynRunPath || dynRPath) {
1027 if (dynRunPath) dynRunPath->d_un.d_val = shdrDynStr.sh_size;
1028 if (dynRPath) dynRPath->d_un.d_val = shdrDynStr.sh_size;
1029 }
1030
1031 else {
1032 /* There is no DT_RUNPATH entry in the .dynamic section, so we
1033 have to grow the .dynamic section. */
1034 string & newDynamic = replaceSection(".dynamic",
1035 rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
1036
1037 unsigned int idx = 0;
1038 for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
1039 debug("DT_NULL index is %d\n", idx);
1040
1041 /* Shift all entries down by one. */
1042 setSubstr(newDynamic, sizeof(Elf_Dyn),
1043 string(newDynamic, 0, sizeof(Elf_Dyn) * (idx + 1)));
1044
1045 /* Add the DT_RUNPATH entry at the top. */
1046 Elf_Dyn newDyn;
1047 wri(newDyn.d_tag, forceRPath ? DT_RPATH : DT_RUNPATH);
1048 newDyn.d_un.d_val = shdrDynStr.sh_size;
1049 setSubstr(newDynamic, 0, string((char *) &newDyn, sizeof(Elf_Dyn)));
1050 }
1051 }
1052
1053
1054 template<ElfFileParams>
removeNeeded(set<string> libs)1055 void ElfFile<ElfFileParamNames>::removeNeeded(set<string> libs)
1056 {
1057 if (libs.empty()) return;
1058
1059 Elf_Shdr & shdrDynamic = findSection(".dynamic");
1060 Elf_Shdr & shdrDynStr = findSection(".dynstr");
1061 char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset);
1062
1063 Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset));
1064 Elf_Dyn * last = dyn;
1065 for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
1066 if (rdi(dyn->d_tag) == DT_NEEDED) {
1067 char * name = strTab + rdi(dyn->d_un.d_val);
1068 if (libs.find(name) != libs.end()) {
1069 debug("removing DT_NEEDED entry `%s'\n", name);
1070 changed = true;
1071 } else {
1072 debug("keeping DT_NEEDED entry `%s'\n", name);
1073 *last++ = *dyn;
1074 }
1075 } else
1076 *last++ = *dyn;
1077 }
1078
1079 memset(last, 0, sizeof(Elf_Dyn) * (dyn - last));
1080 }
1081
1082
1083 static bool printInterpreter = false;
1084 static string newInterpreter;
1085
1086 static bool shrinkRPath = false;
1087 static bool setRPath = false;
1088 static bool printRPath = false;
1089 static string newRPath;
1090 static set<string> neededLibsToRemove;
1091
1092
1093 template<class ElfFile>
patchElf2(ElfFile & elfFile,mode_t fileMode)1094 static void patchElf2(ElfFile & elfFile, mode_t fileMode)
1095 {
1096 elfFile.parse();
1097
1098 if (printInterpreter)
1099 printf("%s\n", elfFile.getInterpreter().c_str());
1100
1101 if (newInterpreter != "")
1102 elfFile.setInterpreter(newInterpreter);
1103
1104 if (printRPath)
1105 elfFile.modifyRPath(elfFile.rpPrint, "");
1106
1107 if (shrinkRPath)
1108 elfFile.modifyRPath(elfFile.rpShrink, "");
1109 else if (setRPath)
1110 elfFile.modifyRPath(elfFile.rpSet, newRPath);
1111
1112 elfFile.removeNeeded(neededLibsToRemove);
1113
1114 if (elfFile.isChanged()){
1115 elfFile.rewriteSections();
1116 writeFile(fileName, fileMode);
1117 }
1118 }
1119
1120
patchElf()1121 static void patchElf()
1122 {
1123 if (!printInterpreter && !printRPath)
1124 debug("patching ELF file `%s'\n", fileName.c_str());
1125
1126 mode_t fileMode;
1127
1128 readFile(fileName, &fileMode);
1129
1130
1131 /* Check the ELF header for basic validity. */
1132 if (fileSize < (off_t) sizeof(Elf32_Ehdr)) error("missing ELF header");
1133
1134 if (memcmp(contents, ELFMAG, SELFMAG) != 0)
1135 error("not an ELF executable");
1136
1137 if (contents[EI_CLASS] == ELFCLASS32 &&
1138 contents[EI_VERSION] == EV_CURRENT)
1139 {
1140 ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym> elfFile;
1141 patchElf2(elfFile, fileMode);
1142 }
1143 else if (contents[EI_CLASS] == ELFCLASS64 &&
1144 contents[EI_VERSION] == EV_CURRENT)
1145 {
1146 ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym> elfFile;
1147 patchElf2(elfFile, fileMode);
1148 }
1149 else {
1150 error("ELF executable is not 32/64-bit, little/big-endian, version 1");
1151 }
1152 }
1153
1154
showHelp(const string & progName)1155 void showHelp(const string & progName)
1156 {
1157 fprintf(stderr, "syntax: %s\n\
1158 [--set-interpreter FILENAME]\n\
1159 [--print-interpreter]\n\
1160 [--set-rpath RPATH]\n\
1161 [--shrink-rpath]\n\
1162 [--print-rpath]\n\
1163 [--force-rpath]\n\
1164 [--remove-needed LIBRARY]\n\
1165 [--debug]\n\
1166 [--version]\n\
1167 FILENAME\n", progName.c_str());
1168 }
1169
1170
main(int argc,char ** argv)1171 int main(int argc, char * * argv)
1172 {
1173 if (argc <= 1) {
1174 showHelp(argv[0]);
1175 return 1;
1176 }
1177
1178 if (getenv("PATCHELF_DEBUG") != 0) debugMode = true;
1179
1180 int i;
1181 for (i = 1; i < argc; ++i) {
1182 string arg(argv[i]);
1183 if (arg == "--set-interpreter" || arg == "--interpreter") {
1184 if (++i == argc) error("missing argument");
1185 newInterpreter = argv[i];
1186 }
1187 else if (arg == "--print-interpreter") {
1188 printInterpreter = true;
1189 }
1190 else if (arg == "--shrink-rpath") {
1191 shrinkRPath = true;
1192 }
1193 else if (arg == "--set-rpath") {
1194 if (++i == argc) error("missing argument");
1195 setRPath = true;
1196 newRPath = argv[i];
1197 }
1198 else if (arg == "--print-rpath") {
1199 printRPath = true;
1200 }
1201 else if (arg == "--force-rpath") {
1202 /* Generally we prefer to emit DT_RUNPATH instead of
1203 DT_RPATH, as the latter is obsolete. However, there is
1204 a slight semantic difference: DT_RUNPATH is "scoped",
1205 it only affects the executable or library in question,
1206 not its recursive imports. So maybe you really want to
1207 force the use of DT_RPATH. That's what this option
1208 does. Without it, DT_RPATH (if encountered) is
1209 converted to DT_RUNPATH, and if neither is present, a
1210 DT_RUNPATH is added. With it, DT_RPATH isn't converted
1211 to DT_RUNPATH, and if neither is present, a DT_RPATH is
1212 added. */
1213 forceRPath = true;
1214 }
1215 else if (arg == "--remove-needed") {
1216 if (++i == argc) error("missing argument");
1217 neededLibsToRemove.insert(argv[i]);
1218 }
1219 else if (arg == "--debug") {
1220 debugMode = true;
1221 }
1222 else if (arg == "--help") {
1223 showHelp(argv[0]);
1224 return 0;
1225 }
1226 else if (arg == "--version") {
1227 printf("1.0\n");
1228 return 0;
1229 }
1230 else break;
1231 }
1232
1233 if (i == argc) error("missing filename");
1234 fileName = argv[i];
1235
1236 patchElf();
1237
1238 return 0;
1239 }
1240