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