1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is elfhack.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2010
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Mike Hommey <mh@glandium.org>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #undef NDEBUG
39 : #include <assert.h>
40 : #include <cstring>
41 : #include <cstdlib>
42 : #include <cstdio>
43 : #include "elfxx.h"
44 :
45 : #define ver "0"
46 : #define elfhack_data ".elfhack.data.v" ver
47 : #define elfhack_text ".elfhack.text.v" ver
48 :
49 : #ifndef R_ARM_V4BX
50 : #define R_ARM_V4BX 0x28
51 : #endif
52 : #ifndef R_ARM_THM_JUMP24
53 : #define R_ARM_THM_JUMP24 0x1e
54 : #endif
55 :
56 : char *rundir = NULL;
57 :
58 : template <typename T>
59 0 : struct wrapped {
60 : T value;
61 : };
62 :
63 : class Elf_Addr_Traits {
64 : public:
65 : typedef wrapped<Elf32_Addr> Type32;
66 : typedef wrapped<Elf64_Addr> Type64;
67 :
68 : template <class endian, typename R, typename T>
69 0 : static inline void swap(T &t, R &r) {
70 0 : r.value = endian::swap(t.value);
71 0 : }
72 : };
73 :
74 : class Elf_RelHack_Traits {
75 : public:
76 : typedef Elf32_Rel Type32;
77 : typedef Elf32_Rel Type64;
78 :
79 : template <class endian, typename R, typename T>
80 36047 : static inline void swap(T &t, R &r) {
81 36047 : r.r_offset = endian::swap(t.r_offset);
82 36047 : r.r_info = endian::swap(t.r_info);
83 36047 : }
84 : };
85 :
86 : typedef serializable<Elf_RelHack_Traits> Elf_RelHack;
87 :
88 42 : class ElfRelHack_Section: public ElfSection {
89 : public:
90 21 : ElfRelHack_Section(Elf_Shdr &s)
91 21 : : ElfSection(s, NULL, NULL)
92 : {
93 21 : name = elfhack_data;
94 21 : };
95 :
96 4 : void serialize(std::ofstream &file, char ei_class, char ei_data)
97 : {
98 72102 : for (std::vector<Elf_RelHack>::iterator i = rels.begin();
99 36051 : i != rels.end(); ++i)
100 36047 : (*i).serialize(file, ei_class, ei_data);
101 4 : }
102 :
103 79 : bool isRelocatable() {
104 79 : return true;
105 : }
106 :
107 42350 : void push_back(Elf_RelHack &r) {
108 42350 : rels.push_back(r);
109 42350 : shdr.sh_size = rels.size() * shdr.sh_entsize;
110 42350 : }
111 : private:
112 : std::vector<Elf_RelHack> rels;
113 : };
114 :
115 : class ElfRelHackCode_Section: public ElfSection {
116 : public:
117 21 : ElfRelHackCode_Section(Elf_Shdr &s, Elf &e)
118 21 : : ElfSection(s, NULL, NULL), parent(e) {
119 42 : std::string file(rundir);
120 21 : init = parent.getDynSection()->getSectionForType(DT_INIT);
121 21 : file += "/inject/";
122 21 : switch (parent.getMachine()) {
123 : case EM_386:
124 21 : file += "x86";
125 21 : break;
126 : case EM_X86_64:
127 0 : file += "x86_64";
128 0 : break;
129 : case EM_ARM:
130 0 : file += "arm";
131 0 : break;
132 : default:
133 0 : throw std::runtime_error("unsupported architecture");
134 : }
135 21 : if (init == NULL)
136 0 : file += "-noinit";
137 21 : file += ".o";
138 42 : std::ifstream inject(file.c_str(), std::ios::in|std::ios::binary);
139 21 : elf = new Elf(inject);
140 21 : if (elf->getType() != ET_REL)
141 0 : throw std::runtime_error("object for injected code is not ET_REL");
142 21 : if (elf->getMachine() != parent.getMachine())
143 0 : throw std::runtime_error("architecture of object for injected code doesn't match");
144 :
145 21 : ElfSymtab_Section *symtab = NULL;
146 :
147 : // Get all executable sections from the injected code object.
148 : // Most of the time, there will only be one for the init function,
149 : // but on e.g. x86, there is a separate section for
150 : // __i686.get_pc_thunk.$reg
151 : // Find the symbol table at the same time.
152 273 : for (ElfSection *section = elf->getSection(1); section != NULL;
153 252 : section = section->getNext()) {
154 357 : if ((section->getType() == SHT_PROGBITS) &&
155 105 : (section->getFlags() & SHF_EXECINSTR)) {
156 42 : code.push_back(section);
157 : // We need to align this section depending on the greater
158 : // alignment required by code sections.
159 42 : if (shdr.sh_addralign < section->getAddrAlign())
160 21 : shdr.sh_addralign = section->getAddrAlign();
161 210 : } else if (section->getType() == SHT_SYMTAB) {
162 21 : symtab = (ElfSymtab_Section *) section;
163 : }
164 : }
165 21 : assert(code.size() != 0);
166 21 : if (symtab == NULL)
167 0 : throw std::runtime_error("Couldn't find a symbol table for the injected code");
168 :
169 : // Find the init symbol
170 21 : entry_point = -1;
171 21 : int shndx = 0;
172 21 : Elf_SymValue *sym = symtab->lookup("init");
173 21 : if (sym) {
174 21 : entry_point = sym->value.getValue();
175 21 : shndx = sym->value.getSection()->getIndex();
176 : } else
177 0 : throw std::runtime_error("Couldn't find an 'init' symbol in the injected code");
178 :
179 : // Adjust code sections offsets according to their size
180 21 : std::vector<ElfSection *>::iterator c = code.begin();
181 21 : (*c)->getShdr().sh_addr = 0;
182 42 : for(ElfSection *last = *(c++); c != code.end(); c++) {
183 21 : unsigned int addr = last->getShdr().sh_addr + last->getSize();
184 21 : if (addr & ((*c)->getAddrAlign() - 1))
185 0 : addr = (addr | ((*c)->getAddrAlign() - 1)) + 1;
186 21 : (*c)->getShdr().sh_addr = addr;
187 : }
188 21 : shdr.sh_size = code.back()->getAddr() + code.back()->getSize();
189 21 : data = new char[shdr.sh_size];
190 21 : char *buf = data;
191 63 : for (c = code.begin(); c != code.end(); c++) {
192 42 : memcpy(buf, (*c)->getData(), (*c)->getSize());
193 42 : buf += (*c)->getSize();
194 42 : if ((*c)->getIndex() < shndx)
195 0 : entry_point += (*c)->getSize();
196 : }
197 21 : name = elfhack_text;
198 21 : }
199 :
200 63 : ~ElfRelHackCode_Section() {
201 21 : delete elf;
202 42 : }
203 :
204 4 : void serialize(std::ofstream &file, char ei_class, char ei_data)
205 : {
206 : // Readjust code offsets
207 12 : for (std::vector<ElfSection *>::iterator c = code.begin(); c != code.end(); c++)
208 8 : (*c)->getShdr().sh_addr += getAddr();
209 :
210 : // Apply relocations
211 52 : for (ElfSection *rel = elf->getSection(1); rel != NULL; rel = rel->getNext())
212 48 : if ((rel->getType() == SHT_REL) || (rel->getType() == SHT_RELA)) {
213 4 : ElfSection *section = rel->getInfo().section;
214 4 : if ((section->getType() == SHT_PROGBITS) && (section->getFlags() & SHF_EXECINSTR)) {
215 4 : if (rel->getType() == SHT_REL)
216 4 : apply_relocations((ElfRel_Section<Elf_Rel> *)rel, section);
217 : else
218 0 : apply_relocations((ElfRel_Section<Elf_Rela> *)rel, section);
219 : }
220 : }
221 :
222 4 : ElfSection::serialize(file, ei_class, ei_data);
223 4 : }
224 :
225 79 : bool isRelocatable() {
226 79 : return true;
227 : }
228 :
229 21 : unsigned int getEntryPoint() {
230 21 : return entry_point;
231 : }
232 : private:
233 : class pc32_relocation {
234 : public:
235 12 : Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
236 : Elf32_Word addend, unsigned int addr)
237 : {
238 12 : return addr + addend - offset - base_addr;
239 : }
240 : };
241 :
242 : class arm_plt32_relocation {
243 : public:
244 0 : Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
245 : Elf32_Word addend, unsigned int addr)
246 : {
247 : // We don't care about sign_extend because the only case where this is
248 : // going to be used only jumps forward.
249 0 : Elf32_Addr tmp = (Elf32_Addr) (addr - offset - base_addr) >> 2;
250 0 : tmp = (addend + tmp) & 0x00ffffff;
251 0 : return (addend & 0xff000000) | tmp;
252 : }
253 : };
254 :
255 : class arm_thm_jump24_relocation {
256 : public:
257 0 : Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
258 : Elf32_Word addend, unsigned int addr)
259 : {
260 : /* Follows description of b.w instructions as per
261 : ARM Architecture Reference Manual ARMĀ® v7-A and ARMĀ® v7-R edition, A8.6.16
262 : We limit ourselves to Encoding T3.
263 : We don't care about sign_extend because the only case where this is
264 : going to be used only jumps forward. */
265 0 : Elf32_Addr tmp = (Elf32_Addr) (addr - offset - base_addr);
266 0 : unsigned int word0 = addend & 0xffff,
267 0 : word1 = addend >> 16;
268 :
269 0 : if (((word0 & 0xf800) != 0xf000) || ((word1 & 0xd000) != 0x9000))
270 0 : throw std::runtime_error("R_ARM_THM_JUMP24 relocation only supported for B.W <label>");
271 :
272 0 : unsigned int s = (word0 & (1 << 10)) >> 10;
273 0 : unsigned int j1 = (word1 & (1 << 13)) >> 13;
274 0 : unsigned int j2 = (word1 & (1 << 11)) >> 11;
275 0 : unsigned int i1 = j1 ^ s ? 0 : 1;
276 0 : unsigned int i2 = j2 ^ s ? 0 : 1;
277 :
278 0 : tmp += ((s << 24) | (i1 << 23) | (i2 << 22) | ((word0 & 0x3ff) << 12) | ((word1 & 0x7ff) << 1));
279 :
280 0 : s = (tmp & (1 << 24)) >> 24;
281 0 : j1 = ((tmp & (1 << 23)) >> 23) ^ !s;
282 0 : j2 = ((tmp & (1 << 22)) >> 22) ^ !s;
283 :
284 : return 0xf000 | (s << 10) | ((tmp & (0x3ff << 12)) >> 12) |
285 0 : (0x9000 << 16) | (j1 << 29) | (j2 << 27) | ((tmp & 0xffe) << 15);
286 : }
287 : };
288 :
289 : class gotoff_relocation {
290 : public:
291 12 : Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
292 : Elf32_Word addend, unsigned int addr)
293 : {
294 12 : return addr + addend;
295 : }
296 : };
297 :
298 : template <class relocation_type>
299 24 : void apply_relocation(ElfSection *the_code, char *base, Elf_Rel *r, unsigned int addr)
300 : {
301 : relocation_type relocation;
302 : Elf32_Addr value;
303 24 : memcpy(&value, base + r->r_offset, 4);
304 24 : value = relocation(the_code->getAddr(), r->r_offset, value, addr);
305 24 : memcpy(base + r->r_offset, &value, 4);
306 24 : }
307 :
308 : template <class relocation_type>
309 0 : void apply_relocation(ElfSection *the_code, char *base, Elf_Rela *r, unsigned int addr)
310 : {
311 : relocation_type relocation;
312 0 : Elf32_Addr value = relocation(the_code->getAddr(), r->r_offset, r->r_addend, addr);
313 0 : memcpy(base + r->r_offset, &value, 4);
314 0 : }
315 :
316 : template <typename Rel_Type>
317 4 : void apply_relocations(ElfRel_Section<Rel_Type> *rel, ElfSection *the_code)
318 : {
319 4 : assert(rel->getType() == Rel_Type::sh_type);
320 4 : char *buf = data + (the_code->getAddr() - code.front()->getAddr());
321 : // TODO: various checks on the sections
322 4 : ElfSymtab_Section *symtab = (ElfSymtab_Section *)rel->getLink();
323 28 : for (typename std::vector<Rel_Type>::iterator r = rel->rels.begin(); r != rel->rels.end(); r++) {
324 : // TODO: various checks on the symbol
325 24 : const char *name = symtab->syms[ELF32_R_SYM(r->r_info)].name;
326 : unsigned int addr;
327 24 : if (symtab->syms[ELF32_R_SYM(r->r_info)].value.getSection() == NULL) {
328 20 : if (strcmp(name, "relhack") == 0) {
329 8 : addr = getNext()->getAddr();
330 12 : } else if (strcmp(name, "elf_header") == 0) {
331 : // TODO: change this ungly hack to something better
332 4 : ElfSection *ehdr = parent.getSection(1)->getPrevious()->getPrevious();
333 4 : addr = ehdr->getAddr();
334 8 : } else if (strcmp(name, "original_init") == 0) {
335 4 : addr = init->getAddr();
336 4 : } else if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") == 0) {
337 : // We actually don't need a GOT, but need it as a reference for
338 : // GOTOFF relocations. We'll just use the start of the ELF file
339 4 : addr = 0;
340 0 : } else if (strcmp(name, "") == 0) {
341 : // This is for R_ARM_V4BX, until we find something better
342 0 : addr = -1;
343 : } else {
344 0 : throw std::runtime_error("Unsupported symbol in relocation");
345 : }
346 : } else {
347 4 : ElfSection *section = symtab->syms[ELF32_R_SYM(r->r_info)].value.getSection();
348 4 : assert((section->getType() == SHT_PROGBITS) && (section->getFlags() & SHF_EXECINSTR));
349 4 : addr = symtab->syms[ELF32_R_SYM(r->r_info)].value.getValue();
350 : }
351 : // Do the relocation
352 : #define REL(machine, type) (EM_ ## machine | (R_ ## machine ## _ ## type << 8))
353 24 : switch (elf->getMachine() | (ELF32_R_TYPE(r->r_info) << 8)) {
354 : case REL(X86_64, PC32):
355 : case REL(386, PC32):
356 : case REL(386, GOTPC):
357 : case REL(ARM, GOTPC):
358 : case REL(ARM, REL32):
359 12 : apply_relocation<pc32_relocation>(the_code, buf, &*r, addr);
360 12 : break;
361 : case REL(ARM, PLT32):
362 0 : apply_relocation<arm_plt32_relocation>(the_code, buf, &*r, addr);
363 0 : break;
364 : case REL(ARM, THM_JUMP24):
365 0 : apply_relocation<arm_thm_jump24_relocation>(the_code, buf, &*r, addr);
366 0 : break;
367 : case REL(386, GOTOFF):
368 : case REL(ARM, GOTOFF):
369 12 : apply_relocation<gotoff_relocation>(the_code, buf, &*r, addr);
370 12 : break;
371 : case REL(ARM, V4BX):
372 : // Ignore R_ARM_V4BX relocations
373 0 : break;
374 : default:
375 0 : throw std::runtime_error("Unsupported relocation type");
376 : }
377 : }
378 4 : }
379 :
380 : Elf *elf, &parent;
381 : std::vector<ElfSection *> code;
382 : ElfSection *init;
383 : int entry_point;
384 : };
385 :
386 : template <typename Rel_Type>
387 21 : int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type2)
388 : {
389 21 : ElfDynamic_Section *dyn = elf->getDynSection();
390 21 : if (dyn ==NULL) {
391 0 : fprintf(stderr, "Couldn't find SHT_DYNAMIC section\n");
392 0 : return -1;
393 : }
394 :
395 21 : ElfSegment *relro = elf->getSegmentByType(PT_GNU_RELRO);
396 :
397 21 : ElfRel_Section<Rel_Type> *section = (ElfRel_Section<Rel_Type> *)dyn->getSectionForType(Rel_Type::d_tag);
398 21 : assert(section->getType() == Rel_Type::sh_type);
399 :
400 : Elf32_Shdr relhack32_section =
401 : { 0, SHT_PROGBITS, SHF_ALLOC, 0, (Elf32_Off)-1, 0, SHN_UNDEF, 0,
402 21 : Elf_RelHack::size(elf->getClass()), Elf_RelHack::size(elf->getClass()) }; // TODO: sh_addralign should be an alignment, not size
403 : Elf32_Shdr relhackcode32_section =
404 : { 0, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0, (Elf32_Off)-1, 0,
405 21 : SHN_UNDEF, 0, 1, 0 };
406 21 : Elf_Shdr relhack_section(relhack32_section);
407 21 : Elf_Shdr relhackcode_section(relhackcode32_section);
408 21 : ElfRelHack_Section *relhack = new ElfRelHack_Section(relhack_section);
409 21 : ElfRelHackCode_Section *relhackcode = new ElfRelHackCode_Section(relhackcode_section, *elf);
410 :
411 21 : ElfSymtab_Section *symtab = (ElfSymtab_Section *) section->getLink();
412 21 : Elf_SymValue *sym = symtab->lookup("__cxa_pure_virtual");
413 :
414 42 : std::vector<Rel_Type> new_rels;
415 21 : Elf_RelHack relhack_entry;
416 21 : relhack_entry.r_offset = relhack_entry.r_info = 0;
417 21 : int entry_sz = (elf->getClass() == ELFCLASS32) ? 4 : 8;
418 311624 : for (typename std::vector<Rel_Type>::iterator i = section->rels.begin();
419 : i != section->rels.end(); i++) {
420 : // We don't need to keep R_*_NONE relocations
421 311603 : if (!ELF32_R_TYPE(i->r_info))
422 0 : continue;
423 311603 : ElfSection *section = elf->getSectionAt(i->r_offset);
424 : // __cxa_pure_virtual is a function used in vtables to point at pure
425 : // virtual methods. The __cxa_pure_virtual function usually abort()s.
426 : // These functions are however normally never called. In the case
427 : // where they would, jumping to the NULL address instead of calling
428 : // __cxa_pure_virtual is going to work just as well. So we can remove
429 : // relocations for the __cxa_pure_virtual symbol and NULL out the
430 : // content at the offset pointed by the relocation.
431 311603 : if (sym) {
432 299981 : if (sym->defined) {
433 : // If we are statically linked to libstdc++, the
434 : // __cxa_pure_virtual symbol is defined in our lib, and we
435 : // have relative relocations (rel_type) for it.
436 0 : if (ELF32_R_TYPE(i->r_info) == rel_type) {
437 0 : serializable<Elf_Addr_Traits> addr(§ion->getData()[i->r_offset - section->getAddr()], entry_sz, elf->getClass(), elf->getData());
438 0 : if (addr.value == sym->value.getValue()) {
439 0 : memset((char *)§ion->getData()[i->r_offset - section->getAddr()], 0, entry_sz);
440 0 : continue;
441 : }
442 : }
443 : } else {
444 : // If we are dynamically linked to libstdc++, the
445 : // __cxa_pure_virtual symbol is undefined in our lib, and we
446 : // have absolute relocations (rel_type2) for it.
447 299981 : if ((ELF32_R_TYPE(i->r_info) == rel_type2) &&
448 : (sym == &symtab->syms[ELF32_R_SYM(i->r_info)])) {
449 31375 : memset((char *)§ion->getData()[i->r_offset - section->getAddr()], 0, entry_sz);
450 31375 : continue;
451 : }
452 : }
453 : }
454 : // Don't pack relocations happening in non writable sections.
455 : // Our injected code is likely not to be allowed to write there.
456 280228 : if (!(section->getFlags() & SHF_WRITE) || (ELF32_R_TYPE(i->r_info) != rel_type) ||
457 : (relro && (i->r_offset >= relro->getAddr()) &&
458 : (i->r_offset < relro->getAddr() + relro->getMemSize())))
459 2988 : new_rels.push_back(*i);
460 : else {
461 : // TODO: check that i->r_addend == *i->r_offset
462 277240 : if (i->r_offset == relhack_entry.r_offset + relhack_entry.r_info * entry_sz) {
463 234911 : relhack_entry.r_info++;
464 : } else {
465 42329 : if (relhack_entry.r_offset)
466 42308 : relhack->push_back(relhack_entry);
467 42329 : relhack_entry.r_offset = i->r_offset;
468 42329 : relhack_entry.r_info = 1;
469 : }
470 : }
471 : }
472 21 : if (relhack_entry.r_offset)
473 21 : relhack->push_back(relhack_entry);
474 : // Last entry must be NULL
475 21 : relhack_entry.r_offset = relhack_entry.r_info = 0;
476 21 : relhack->push_back(relhack_entry);
477 :
478 21 : relhackcode->insertAfter(section);
479 21 : relhack->insertAfter(relhackcode);
480 :
481 21 : unsigned int old_end = section->getOffset() + section->getSize();
482 21 : section->rels.assign(new_rels.begin(), new_rels.end());
483 21 : section->shrink(new_rels.size() * section->getEntSize());
484 21 : ElfLocation *init = new ElfLocation(relhackcode, relhackcode->getEntryPoint());
485 21 : dyn->setValueForType(DT_INIT, init);
486 : // TODO: adjust the value according to the remaining number of relative relocations
487 21 : if (dyn->getValueForType(Rel_Type::d_tag_count))
488 21 : dyn->setValueForType(Rel_Type::d_tag_count, new ElfPlainValue(0));
489 :
490 21 : if (relhack->getOffset() + relhack->getSize() >= old_end) {
491 3 : fprintf(stderr, "No gain. Skipping\n");
492 3 : return -1;
493 : }
494 18 : return 0;
495 : }
496 :
497 1 : static inline int backup_file(const char *name)
498 : {
499 2 : std::string fname(name);
500 1 : fname += ".bak";
501 1 : return rename(name, fname.c_str());
502 : }
503 :
504 21 : void do_file(const char *name, bool backup = false, bool force = false)
505 : {
506 42 : std::ifstream file(name, std::ios::in|std::ios::binary);
507 21 : Elf *elf = new Elf(file);
508 21 : unsigned int size = elf->getSize();
509 21 : fprintf(stderr, "%s: ", name);
510 21 : if (elf->getType() != ET_DYN) {
511 0 : fprintf(stderr, "Not a shared object. Skipping\n");
512 0 : delete elf;
513 : return;
514 : }
515 :
516 797 : for (ElfSection *section = elf->getSection(1); section != NULL;
517 : section = section->getNext()) {
518 1531 : if (section->getName() &&
519 755 : (strncmp(section->getName(), ".elfhack.", 9) == 0)) {
520 0 : fprintf(stderr, "Already elfhacked. Skipping\n");
521 0 : delete elf;
522 : return;
523 : }
524 : }
525 :
526 21 : int exit = -1;
527 21 : switch (elf->getMachine()) {
528 : case EM_386:
529 21 : exit = do_relocation_section<Elf_Rel>(elf, R_386_RELATIVE, R_386_32);
530 21 : break;
531 : case EM_X86_64:
532 0 : exit = do_relocation_section<Elf_Rela>(elf, R_X86_64_RELATIVE, R_X86_64_64);
533 0 : break;
534 : case EM_ARM:
535 0 : exit = do_relocation_section<Elf_Rel>(elf, R_ARM_RELATIVE, R_ARM_ABS32);
536 0 : break;
537 : }
538 21 : if (exit == 0) {
539 18 : if (!force && (elf->getSize() >= size)) {
540 14 : fprintf(stderr, "No gain. Skipping\n");
541 4 : } else if (backup && backup_file(name) != 0) {
542 0 : fprintf(stderr, "Couln't create backup file\n");
543 : } else {
544 8 : std::ofstream ofile(name, std::ios::out|std::ios::binary|std::ios::trunc);
545 4 : elf->write(ofile);
546 4 : fprintf(stderr, "Reduced by %d bytes\n", size - elf->getSize());
547 : }
548 : }
549 21 : delete elf;
550 : }
551 :
552 2 : int main(int argc, char *argv[])
553 : {
554 : int arg;
555 2 : bool backup = false;
556 2 : bool force = false;
557 2 : char *lastSlash = rindex(argv[0], '/');
558 2 : if (lastSlash != NULL)
559 2 : rundir = strndup(argv[0], lastSlash - argv[0]);
560 25 : for (arg = 1; arg < argc; arg++) {
561 23 : if (strcmp(argv[arg], "-f") == 0)
562 1 : force = true;
563 22 : else if (strcmp(argv[arg], "-b") == 0)
564 1 : backup = true;
565 : else
566 21 : do_file(argv[arg], backup, force);
567 : }
568 :
569 2 : free(rundir);
570 2 : return 0;
571 6 : }
|