Bug 1869647 - Mark hasStorageAccess.sub.https.window.html as intermittent after wpt...
[gecko.git] / build / unix / elfhack / elfhack.cpp
blob719d4ac8f5c4a9ec7ae50c83c481fe9f53bb9c80
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #undef NDEBUG
6 #include <assert.h>
7 #include <cstring>
8 #include <cstdlib>
9 #include <cstdio>
10 #include <memory>
12 #include "elfxx.h"
13 #include "mozilla/CheckedInt.h"
15 #define ver "1"
16 #define elfhack_data ".elfhack.data.v" ver
17 #define elfhack_text ".elfhack.text.v" ver
19 #ifndef R_ARM_V4BX
20 # define R_ARM_V4BX 0x28
21 #endif
22 #ifndef R_ARM_CALL
23 # define R_ARM_CALL 0x1c
24 #endif
25 #ifndef R_ARM_JUMP24
26 # define R_ARM_JUMP24 0x1d
27 #endif
28 #ifndef R_ARM_THM_JUMP24
29 # define R_ARM_THM_JUMP24 0x1e
30 #endif
32 char* rundir = nullptr;
34 template <typename T>
35 struct wrapped {
36 T value;
39 class Elf_Addr_Traits {
40 public:
41 typedef wrapped<Elf32_Addr> Type32;
42 typedef wrapped<Elf64_Addr> Type64;
44 template <class endian, typename R, typename T>
45 static inline void swap(T& t, R& r) {
46 r.value = endian::swap(t.value);
50 typedef serializable<Elf_Addr_Traits> Elf_Addr;
52 class ElfRelHack_Section : public ElfSection {
53 public:
54 ElfRelHack_Section(Elf_Shdr& s)
55 : ElfSection(s, nullptr, nullptr),
56 block_size((8 * s.sh_entsize - 1) * s.sh_entsize) {
57 name = elfhack_data;
60 void serialize(std::ofstream& file, unsigned char ei_class,
61 unsigned char ei_data) {
62 if (bitmap) {
63 relr.push_back((bitmap << 1) | 1);
65 for (std::vector<Elf64_Addr>::iterator i = relr.begin(); i != relr.end();
66 ++i) {
67 Elf_Addr out;
68 out.value = *i;
69 out.serialize(file, ei_class, ei_data);
73 bool isRelocatable() { return true; }
75 void push_back(Elf64_Addr offset) {
76 // The format used for the packed relocations is SHT_RELR, described in
77 // https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
78 // The gist of it is that an address is recorded, and the following words,
79 // if their LSB is 1, represent a bitmap of word-size-spaced relocations
80 // at the addresses that follow. There can be multiple such bitmaps, such
81 // that very long streaks of (possibly spaced) relocations can be recorded
82 // in a very compact way.
83 for (;;) {
84 // [block_start; block_start + block_size] represents the range of offsets
85 // the current bitmap can record. If the offset doesn't fall in that
86 // range, or if doesn't align properly to be recorded, we record the
87 // bitmap, and slide the block corresponding to a new bitmap. If the
88 // offset doesn't fall in the range for the new bitmap, or if there wasn't
89 // an active bitmap in the first place, we record the offset and start a
90 // new bitmap for the block that follows it.
91 if (!block_start || offset < block_start ||
92 offset >= block_start + block_size ||
93 (offset - block_start) % shdr.sh_entsize) {
94 if (bitmap) {
95 relr.push_back((bitmap << 1) | 1);
96 block_start += block_size;
97 bitmap = 0;
98 continue;
100 relr.push_back(offset);
101 block_start = offset + shdr.sh_entsize;
102 break;
104 bitmap |= 1ULL << ((offset - block_start) / shdr.sh_entsize);
105 break;
107 shdr.sh_size = (relr.size() + (bitmap ? 1 : 0)) * shdr.sh_entsize;
110 private:
111 std::vector<Elf64_Addr> relr;
112 size_t block_size;
113 Elf64_Addr block_start = 0;
114 Elf64_Addr bitmap = 0;
117 class ElfRelHackCode_Section : public ElfSection {
118 public:
119 ElfRelHackCode_Section(Elf_Shdr& s, Elf& e,
120 ElfRelHack_Section& relhack_section, unsigned int init,
121 unsigned int mprotect_cb, unsigned int sysconf_cb)
122 : ElfSection(s, nullptr, nullptr),
123 parent(e),
124 relhack_section(relhack_section),
125 init(init),
126 init_trampoline(nullptr),
127 mprotect_cb(mprotect_cb),
128 sysconf_cb(sysconf_cb) {
129 std::string file(rundir);
130 file += "/inject/";
131 switch (parent.getMachine()) {
132 case EM_386:
133 file += "x86";
134 break;
135 case EM_X86_64:
136 file += "x86_64";
137 break;
138 case EM_ARM:
139 file += "arm";
140 break;
141 case EM_AARCH64:
142 file += "aarch64";
143 break;
144 default:
145 throw std::runtime_error("unsupported architecture");
147 file += ".o";
148 std::ifstream inject(file.c_str(), std::ios::in | std::ios::binary);
149 elf = new Elf(inject);
150 if (elf->getType() != ET_REL)
151 throw std::runtime_error("object for injected code is not ET_REL");
152 if (elf->getMachine() != parent.getMachine())
153 throw std::runtime_error(
154 "architecture of object for injected code doesn't match");
156 ElfSymtab_Section* symtab = nullptr;
158 // Find the symbol table.
159 for (ElfSection* section = elf->getSection(1); section != nullptr;
160 section = section->getNext()) {
161 if (section->getType() == SHT_SYMTAB)
162 symtab = (ElfSymtab_Section*)section;
164 if (symtab == nullptr)
165 throw std::runtime_error(
166 "Couldn't find a symbol table for the injected code");
168 relro = parent.getSegmentByType(PT_GNU_RELRO);
170 // Find the init symbol
171 entry_point = -1;
172 std::string symbol = "init";
173 if (!init) symbol += "_noinit";
174 if (relro) symbol += "_relro";
175 Elf_SymValue* sym = symtab->lookup(symbol.c_str());
176 if (!sym)
177 throw std::runtime_error(
178 "Couldn't find an 'init' symbol in the injected code");
180 entry_point = sym->value.getValue();
182 // Get all relevant sections from the injected code object.
183 add_code_section(sym->value.getSection());
185 // If the original init function is located too far away, we're going to
186 // need to use a trampoline. See comment in inject.c.
187 // Theoretically, we should check for (init - instr) > boundary, where
188 // boundary is the platform-dependent limit, and instr is the virtual
189 // address of the instruction that calls the original init, but we don't
190 // have it at this point, so punt to just init.
191 if ((init > 0xffffff && parent.getMachine() == EM_ARM) ||
192 (init > 0x07ffffff && parent.getMachine() == EM_AARCH64)) {
193 Elf_SymValue* trampoline = symtab->lookup("init_trampoline");
194 if (!trampoline) {
195 throw std::runtime_error(
196 "Couldn't find an 'init_trampoline' symbol in the injected code");
199 init_trampoline = trampoline->value.getSection();
200 add_code_section(init_trampoline);
203 // Adjust code sections offsets according to their size
204 std::vector<ElfSection*>::iterator c = code.begin();
205 (*c)->getShdr().sh_addr = 0;
206 for (ElfSection* last = *(c++); c != code.end(); ++c) {
207 unsigned int addr = last->getShdr().sh_addr + last->getSize();
208 if (addr & ((*c)->getAddrAlign() - 1))
209 addr = (addr | ((*c)->getAddrAlign() - 1)) + 1;
210 (*c)->getShdr().sh_addr = addr;
211 // We need to align this section depending on the greater
212 // alignment required by code sections.
213 if (shdr.sh_addralign < (*c)->getAddrAlign())
214 shdr.sh_addralign = (*c)->getAddrAlign();
215 last = *c;
217 shdr.sh_size = code.back()->getAddr() + code.back()->getSize();
218 data = static_cast<char*>(malloc(shdr.sh_size));
219 if (!data) {
220 throw std::runtime_error("Could not malloc ElfSection data");
222 char* buf = data;
223 for (c = code.begin(); c != code.end(); ++c) {
224 memcpy(buf, (*c)->getData(), (*c)->getSize());
225 buf += (*c)->getSize();
227 name = elfhack_text;
230 ~ElfRelHackCode_Section() { delete elf; }
232 void serialize(std::ofstream& file, unsigned char ei_class,
233 unsigned char ei_data) override {
234 // Readjust code offsets
235 for (std::vector<ElfSection*>::iterator c = code.begin(); c != code.end();
236 ++c)
237 (*c)->getShdr().sh_addr += getAddr();
239 // Apply relocations
240 for (std::vector<ElfSection*>::iterator c = code.begin(); c != code.end();
241 ++c) {
242 for (ElfSection* rel = elf->getSection(1); rel != nullptr;
243 rel = rel->getNext())
244 if (((rel->getType() == SHT_REL) || (rel->getType() == SHT_RELA)) &&
245 (rel->getInfo().section == *c)) {
246 if (rel->getType() == SHT_REL)
247 apply_relocations((ElfRel_Section<Elf_Rel>*)rel, *c);
248 else
249 apply_relocations((ElfRel_Section<Elf_Rela>*)rel, *c);
253 ElfSection::serialize(file, ei_class, ei_data);
256 bool isRelocatable() override { return false; }
258 unsigned int getEntryPoint() { return entry_point; }
260 void insertBefore(ElfSection* section, bool dirty = true) override {
261 // Adjust the address so that this section is adjacent to the one it's
262 // being inserted before. This avoids creating holes which subsequently
263 // might lead the PHDR-adjusting code to create unnecessary additional
264 // PT_LOADs.
265 shdr.sh_addr =
266 (section->getAddr() - shdr.sh_size) & ~(shdr.sh_addralign - 1);
267 ElfSection::insertBefore(section, dirty);
270 private:
271 void add_code_section(ElfSection* section) {
272 if (section) {
273 /* Don't add section if it's already been added in the past */
274 for (auto s = code.begin(); s != code.end(); ++s) {
275 if (section == *s) return;
277 code.push_back(section);
278 find_code(section);
282 /* Look at the relocations associated to the given section to find other
283 * sections that it requires */
284 void find_code(ElfSection* section) {
285 for (ElfSection* s = elf->getSection(1); s != nullptr; s = s->getNext()) {
286 if (((s->getType() == SHT_REL) || (s->getType() == SHT_RELA)) &&
287 (s->getInfo().section == section)) {
288 if (s->getType() == SHT_REL)
289 scan_relocs_for_code((ElfRel_Section<Elf_Rel>*)s);
290 else
291 scan_relocs_for_code((ElfRel_Section<Elf_Rela>*)s);
296 template <typename Rel_Type>
297 void scan_relocs_for_code(ElfRel_Section<Rel_Type>* rel) {
298 ElfSymtab_Section* symtab = (ElfSymtab_Section*)rel->getLink();
299 for (auto r = rel->rels.begin(); r != rel->rels.end(); ++r) {
300 ElfSection* section =
301 symtab->syms[ELF64_R_SYM(r->r_info)].value.getSection();
302 add_code_section(section);
306 // TODO: sort out which non-aarch64 relocation types should be using
307 // `value` (even though in practice it's either 0 or the same as addend)
308 class pc32_relocation {
309 public:
310 Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
311 Elf64_Sxword addend, unsigned int addr,
312 Elf64_Word value) {
313 return addr + addend - offset - base_addr;
317 class arm_plt32_relocation {
318 public:
319 Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
320 Elf64_Sxword addend, unsigned int addr,
321 Elf64_Word value) {
322 // We don't care about sign_extend because the only case where this is
323 // going to be used only jumps forward.
324 Elf32_Addr tmp = (Elf32_Addr)(addr - offset - base_addr) >> 2;
325 tmp = (addend + tmp) & 0x00ffffff;
326 return (addend & 0xff000000) | tmp;
330 class arm_thm_jump24_relocation {
331 public:
332 Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
333 Elf64_Sxword addend, unsigned int addr,
334 Elf64_Word value) {
335 /* Follows description of b.w and bl instructions as per
336 ARM Architecture Reference Manual ARM® v7-A and ARM® v7-R edition,
337 A8.6.16 We limit ourselves to Encoding T4 of b.w and Encoding T1 of bl.
338 We don't care about sign_extend because the only case where this is
339 going to be used only jumps forward. */
340 Elf32_Addr tmp = (Elf32_Addr)(addr - offset - base_addr);
341 unsigned int word0 = addend & 0xffff, word1 = addend >> 16;
343 /* Encoding T4 of B.W is 10x1 ; Encoding T1 of BL is 11x1. */
344 unsigned int type = (word1 & 0xd000) >> 12;
345 if (((word0 & 0xf800) != 0xf000) || ((type & 0x9) != 0x9))
346 throw std::runtime_error(
347 "R_ARM_THM_JUMP24/R_ARM_THM_CALL relocation only supported for B.W "
348 "<label> and BL <label>");
350 /* When the target address points to ARM code, switch a BL to a
351 * BLX. This however can't be done with a B.W without adding a
352 * trampoline, which is not supported as of now. */
353 if ((addr & 0x1) == 0) {
354 if (type == 0x9)
355 throw std::runtime_error(
356 "R_ARM_THM_JUMP24/R_ARM_THM_CALL relocation only supported for "
357 "BL <label> when label points to ARM code");
358 /* The address of the target is always relative to a 4-bytes
359 * aligned address, so if the address of the BL instruction is
360 * not 4-bytes aligned, adjust for it. */
361 if ((base_addr + offset) & 0x2) tmp += 2;
362 /* Encoding T2 of BLX is 11x0. */
363 type = 0xc;
366 unsigned int s = (word0 & (1 << 10)) >> 10;
367 unsigned int j1 = (word1 & (1 << 13)) >> 13;
368 unsigned int j2 = (word1 & (1 << 11)) >> 11;
369 unsigned int i1 = j1 ^ s ? 0 : 1;
370 unsigned int i2 = j2 ^ s ? 0 : 1;
372 tmp += ((s << 24) | (i1 << 23) | (i2 << 22) | ((word0 & 0x3ff) << 12) |
373 ((word1 & 0x7ff) << 1));
375 s = (tmp & (1 << 24)) >> 24;
376 j1 = ((tmp & (1 << 23)) >> 23) ^ !s;
377 j2 = ((tmp & (1 << 22)) >> 22) ^ !s;
379 return 0xf000 | (s << 10) | ((tmp & (0x3ff << 12)) >> 12) | (type << 28) |
380 (j1 << 29) | (j2 << 27) | ((tmp & 0xffe) << 15);
384 class gotoff_relocation {
385 public:
386 Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
387 Elf64_Sxword addend, unsigned int addr,
388 Elf64_Word value) {
389 return addr + addend;
393 template <int start, int end>
394 class abs_lo12_nc_relocation {
395 public:
396 Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
397 Elf64_Sxword addend, unsigned int addr,
398 Elf64_Word value) {
399 // Fill the bits [end:start] of the immediate value in an ADD, LDR or STR
400 // instruction, at bits [21:10].
401 // per ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture
402 // profile C5.6.4, C5.6.83 or C5.6.178 and ELF for the ARM® 64-bit
403 // Architecture (AArch64) 4.6.6, Table 4-9.
404 Elf64_Word mask = (1 << (end + 1)) - 1;
405 return value | (((((addr + addend) & mask) >> start) & 0xfff) << 10);
409 class adr_prel_pg_hi21_relocation {
410 public:
411 Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
412 Elf64_Sxword addend, unsigned int addr,
413 Elf64_Word value) {
414 // Fill the bits [32:12] of the immediate value in a ADRP instruction,
415 // at bits [23:5]+[30:29].
416 // per ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture
417 // profile C5.6.10 and ELF for the ARM® 64-bit Architecture
418 // (AArch64) 4.6.6, Table 4-9.
419 Elf64_Word imm = ((addr + addend) >> 12) - ((base_addr + offset) >> 12);
420 Elf64_Word immLo = (imm & 0x3) << 29;
421 Elf64_Word immHi = (imm & 0x1ffffc) << 3;
422 return value & 0x9f00001f | immLo | immHi;
426 class call26_relocation {
427 public:
428 Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset,
429 Elf64_Sxword addend, unsigned int addr,
430 Elf64_Word value) {
431 // Fill the bits [27:2] of the immediate value in a BL instruction,
432 // at bits [25:0].
433 // per ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture
434 // profile C5.6.26 and ELF for the ARM® 64-bit Architecture
435 // (AArch64) 4.6.6, Table 4-10.
436 return value | (((addr + addend - offset - base_addr) & 0x0ffffffc) >> 2);
440 template <class relocation_type>
441 void apply_relocation(ElfSection* the_code, char* base, Elf_Rel* r,
442 unsigned int addr) {
443 relocation_type relocation;
444 Elf32_Addr value;
445 memcpy(&value, base + r->r_offset, 4);
446 value = relocation(the_code->getAddr(), r->r_offset, value, addr, value);
447 memcpy(base + r->r_offset, &value, 4);
450 template <class relocation_type>
451 void apply_relocation(ElfSection* the_code, char* base, Elf_Rela* r,
452 unsigned int addr) {
453 relocation_type relocation;
454 Elf64_Word value;
455 memcpy(&value, base + r->r_offset, 4);
456 Elf32_Addr new_value =
457 relocation(the_code->getAddr(), r->r_offset, r->r_addend, addr, value);
458 memcpy(base + r->r_offset, &new_value, 4);
461 template <typename Rel_Type>
462 void apply_relocations(ElfRel_Section<Rel_Type>* rel, ElfSection* the_code) {
463 assert(rel->getType() == Rel_Type::sh_type);
464 char* buf = data + (the_code->getAddr() - code.front()->getAddr());
465 // TODO: various checks on the sections
466 ElfSymtab_Section* symtab = (ElfSymtab_Section*)rel->getLink();
467 for (typename std::vector<Rel_Type>::iterator r = rel->rels.begin();
468 r != rel->rels.end(); ++r) {
469 // TODO: various checks on the symbol
470 const char* name = symtab->syms[ELF64_R_SYM(r->r_info)].name;
471 unsigned int addr;
472 if (symtab->syms[ELF64_R_SYM(r->r_info)].value.getSection() == nullptr) {
473 if (strcmp(name, "relhack") == 0) {
474 addr = relhack_section.getAddr();
475 } else if (strcmp(name, "relhack_end") == 0) {
476 addr = relhack_section.getAddr() + relhack_section.getSize();
477 } else if (strcmp(name, "__ehdr_start") == 0) {
478 // TODO: change this ugly hack to something better
479 ElfSection* ehdr = parent.getSection(1)->getPrevious()->getPrevious();
480 addr = ehdr->getAddr();
481 } else if (strcmp(name, "original_init") == 0) {
482 if (init_trampoline) {
483 addr = init_trampoline->getAddr();
484 } else {
485 addr = init;
487 } else if (strcmp(name, "real_original_init") == 0) {
488 addr = init;
489 } else if (relro && strcmp(name, "mprotect_cb") == 0) {
490 addr = mprotect_cb;
491 } else if (relro && strcmp(name, "sysconf_cb") == 0) {
492 addr = sysconf_cb;
493 } else if (relro && strcmp(name, "relro_start") == 0) {
494 addr = relro->getAddr();
495 } else if (relro && strcmp(name, "relro_end") == 0) {
496 addr = (relro->getAddr() + relro->getMemSize());
497 } else if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") == 0) {
498 // We actually don't need a GOT, but need it as a reference for
499 // GOTOFF relocations. We'll just use the start of the ELF file
500 addr = 0;
501 } else if (strcmp(name, "") == 0) {
502 // This is for R_ARM_V4BX, until we find something better
503 addr = -1;
504 } else {
505 throw std::runtime_error("Unsupported symbol in relocation");
507 } else {
508 ElfSection* section =
509 symtab->syms[ELF64_R_SYM(r->r_info)].value.getSection();
510 assert((section->getType() == SHT_PROGBITS) &&
511 (section->getFlags() & SHF_EXECINSTR));
512 addr = symtab->syms[ELF64_R_SYM(r->r_info)].value.getValue();
514 // Do the relocation
515 #define REL(machine, type) (EM_##machine | (R_##machine##_##type << 8))
516 switch (elf->getMachine() | (ELF64_R_TYPE(r->r_info) << 8)) {
517 case REL(X86_64, PC32):
518 case REL(X86_64, PLT32):
519 case REL(386, PC32):
520 case REL(386, GOTPC):
521 case REL(ARM, GOTPC):
522 case REL(ARM, REL32):
523 case REL(AARCH64, PREL32):
524 case REL(AARCH64,
525 PREL64): // In theory PREL64 should have its own relocation
526 // function, but in practice it doesn't matter.
527 apply_relocation<pc32_relocation>(the_code, buf, &*r, addr);
528 break;
529 case REL(ARM, CALL):
530 case REL(ARM, JUMP24):
531 case REL(ARM, PLT32):
532 apply_relocation<arm_plt32_relocation>(the_code, buf, &*r, addr);
533 break;
534 case REL(ARM, THM_PC22 /* THM_CALL */):
535 case REL(ARM, THM_JUMP24):
536 apply_relocation<arm_thm_jump24_relocation>(the_code, buf, &*r, addr);
537 break;
538 case REL(386, GOTOFF):
539 case REL(ARM, GOTOFF):
540 apply_relocation<gotoff_relocation>(the_code, buf, &*r, addr);
541 break;
542 case REL(AARCH64, ADD_ABS_LO12_NC):
543 apply_relocation<abs_lo12_nc_relocation<0, 11>>(the_code, buf, &*r,
544 addr);
545 break;
546 case REL(AARCH64, ADR_PREL_PG_HI21):
547 apply_relocation<adr_prel_pg_hi21_relocation>(the_code, buf, &*r,
548 addr);
549 break;
550 case REL(AARCH64, LDST32_ABS_LO12_NC):
551 apply_relocation<abs_lo12_nc_relocation<2, 11>>(the_code, buf, &*r,
552 addr);
553 break;
554 case REL(AARCH64, LDST64_ABS_LO12_NC):
555 apply_relocation<abs_lo12_nc_relocation<3, 11>>(the_code, buf, &*r,
556 addr);
557 break;
558 case REL(AARCH64, CALL26):
559 apply_relocation<call26_relocation>(the_code, buf, &*r, addr);
560 break;
561 case REL(ARM, V4BX):
562 // Ignore R_ARM_V4BX relocations
563 break;
564 default:
565 throw std::runtime_error("Unsupported relocation type");
570 Elf *elf, &parent;
571 ElfRelHack_Section& relhack_section;
572 std::vector<ElfSection*> code;
573 unsigned int init;
574 ElfSection* init_trampoline;
575 unsigned int mprotect_cb;
576 unsigned int sysconf_cb;
577 int entry_point;
578 ElfSegment* relro;
581 unsigned int get_addend(Elf_Rel* rel, Elf* elf) {
582 ElfLocation loc(rel->r_offset, elf);
583 Elf_Addr addr(loc.getBuffer(), Elf_Addr::size(elf->getClass()),
584 elf->getClass(), elf->getData());
585 return addr.value;
588 unsigned int get_addend(Elf_Rela* rel, Elf* elf) { return rel->r_addend; }
590 void set_relative_reloc(Elf_Rel* rel, Elf* elf, unsigned int value) {
591 ElfLocation loc(rel->r_offset, elf);
592 Elf_Addr addr;
593 addr.value = value;
594 addr.serialize(const_cast<char*>(loc.getBuffer()),
595 Elf_Addr::size(elf->getClass()), elf->getClass(),
596 elf->getData());
599 void set_relative_reloc(Elf_Rela* rel, Elf* elf, unsigned int value) {
600 // ld puts the value of relocated relocations both in the addend and
601 // at r_offset. For consistency, keep it that way.
602 set_relative_reloc((Elf_Rel*)rel, elf, value);
603 rel->r_addend = value;
606 void maybe_split_segment(Elf* elf, ElfSegment* segment) {
607 std::list<ElfSection*>::iterator it = segment->begin();
608 for (ElfSection* last = *(it++); it != segment->end(); last = *(it++)) {
609 // When two consecutive non-SHT_NOBITS sections are apart by more
610 // than the alignment of the section, the second can be moved closer
611 // to the first, but this requires the segment to be split.
612 if (((*it)->getType() != SHT_NOBITS) && (last->getType() != SHT_NOBITS) &&
613 ((*it)->getOffset() - last->getOffset() - last->getSize() >
614 segment->getAlign())) {
615 // Probably very wrong.
616 Elf_Phdr phdr;
617 phdr.p_type = PT_LOAD;
618 phdr.p_vaddr = 0;
619 phdr.p_paddr = phdr.p_vaddr + segment->getVPDiff();
620 phdr.p_flags = segment->getFlags();
621 phdr.p_align = segment->getAlign();
622 phdr.p_filesz = (Elf64_Xword)-1LL;
623 phdr.p_memsz = (Elf64_Xword)-1LL;
624 ElfSegment* newSegment = new ElfSegment(&phdr);
625 elf->insertSegmentAfter(segment, newSegment);
626 for (; it != segment->end(); ++it) {
627 newSegment->addSection(*it);
629 for (it = newSegment->begin(); it != newSegment->end(); ++it) {
630 segment->removeSection(*it);
632 break;
637 // EH_FRAME constants
638 static const unsigned char DW_EH_PE_absptr = 0x00;
639 static const unsigned char DW_EH_PE_omit = 0xff;
641 // Data size
642 static const unsigned char DW_EH_PE_LEB128 = 0x01;
643 static const unsigned char DW_EH_PE_data2 = 0x02;
644 static const unsigned char DW_EH_PE_data4 = 0x03;
645 static const unsigned char DW_EH_PE_data8 = 0x04;
647 // Data signedness
648 static const unsigned char DW_EH_PE_signed = 0x08;
650 // Modifiers
651 static const unsigned char DW_EH_PE_pcrel = 0x10;
653 // Return the data size part of the encoding value
654 static unsigned char encoding_data_size(unsigned char encoding) {
655 return encoding & 0x07;
658 // Advance `step` bytes in the buffer at `data` with size `size`, returning
659 // the advanced buffer pointer and remaining size.
660 // Returns true if step <= size.
661 static bool advance_buffer(char** data, size_t* size, size_t step) {
662 if (step > *size) return false;
664 *data += step;
665 *size -= step;
666 return true;
669 // Advance in the given buffer, skipping the full length of the variable-length
670 // encoded LEB128 type in CIE/FDE data.
671 static bool skip_LEB128(char** data, size_t* size) {
672 if (!*size) return false;
674 while (*size && (*(*data)++ & (char)0x80)) {
675 (*size)--;
677 return true;
680 // Advance in the given buffer, skipping the full length of a pointer encoded
681 // with the given encoding.
682 static bool skip_eh_frame_pointer(char** data, size_t* size,
683 unsigned char encoding) {
684 switch (encoding_data_size(encoding)) {
685 case DW_EH_PE_data2:
686 return advance_buffer(data, size, 2);
687 case DW_EH_PE_data4:
688 return advance_buffer(data, size, 4);
689 case DW_EH_PE_data8:
690 return advance_buffer(data, size, 8);
691 case DW_EH_PE_LEB128:
692 return skip_LEB128(data, size);
694 throw std::runtime_error("unreachable");
697 // Specialized implementations for adjust_eh_frame_pointer().
698 template <typename T>
699 static bool adjust_eh_frame_sized_pointer(char** data, size_t* size,
700 ElfSection* eh_frame,
701 unsigned int origAddr, Elf* elf) {
702 if (*size < sizeof(T)) return false;
704 serializable<FixedSizeData<T>> pointer(*data, *size, elf->getClass(),
705 elf->getData());
706 mozilla::CheckedInt<T> value = pointer.value;
707 if (origAddr < eh_frame->getAddr()) {
708 unsigned int diff = eh_frame->getAddr() - origAddr;
709 value -= diff;
710 } else {
711 unsigned int diff = origAddr - eh_frame->getAddr();
712 value += diff;
714 if (!value.isValid())
715 throw std::runtime_error("Overflow while adjusting eh_frame");
716 pointer.value = value.value();
717 pointer.serialize(*data, *size, elf->getClass(), elf->getData());
718 return advance_buffer(data, size, sizeof(T));
721 // In the given eh_frame section, adjust the pointer with the given encoding,
722 // pointed to by the given buffer (`data`, `size`), considering the eh_frame
723 // section was originally at `origAddr`. Also advances in the buffer.
724 static bool adjust_eh_frame_pointer(char** data, size_t* size,
725 unsigned char encoding,
726 ElfSection* eh_frame, unsigned int origAddr,
727 Elf* elf) {
728 if ((encoding & 0x70) != DW_EH_PE_pcrel)
729 return skip_eh_frame_pointer(data, size, encoding);
731 if (encoding & DW_EH_PE_signed) {
732 switch (encoding_data_size(encoding)) {
733 case DW_EH_PE_data2:
734 return adjust_eh_frame_sized_pointer<int16_t>(data, size, eh_frame,
735 origAddr, elf);
736 case DW_EH_PE_data4:
737 return adjust_eh_frame_sized_pointer<int32_t>(data, size, eh_frame,
738 origAddr, elf);
739 case DW_EH_PE_data8:
740 return adjust_eh_frame_sized_pointer<int64_t>(data, size, eh_frame,
741 origAddr, elf);
743 } else {
744 switch (encoding_data_size(encoding)) {
745 case DW_EH_PE_data2:
746 return adjust_eh_frame_sized_pointer<uint16_t>(data, size, eh_frame,
747 origAddr, elf);
748 case DW_EH_PE_data4:
749 return adjust_eh_frame_sized_pointer<uint32_t>(data, size, eh_frame,
750 origAddr, elf);
751 case DW_EH_PE_data8:
752 return adjust_eh_frame_sized_pointer<uint64_t>(data, size, eh_frame,
753 origAddr, elf);
757 throw std::runtime_error("Unsupported eh_frame pointer encoding");
760 // The eh_frame section may contain "PC"-relative pointers. If we move the
761 // section, those need to be adjusted. Other type of pointers are relative to
762 // sections we don't touch.
763 static void adjust_eh_frame(ElfSection* eh_frame, unsigned int origAddr,
764 Elf* elf) {
765 if (eh_frame->getAddr() == origAddr) // nothing to do;
766 return;
768 char* data = const_cast<char*>(eh_frame->getData());
769 size_t size = eh_frame->getSize();
770 unsigned char LSDAencoding = DW_EH_PE_omit;
771 unsigned char FDEencoding = DW_EH_PE_absptr;
772 bool hasZ = false;
774 // Decoding of eh_frame based on https://www.airs.com/blog/archives/460
775 while (size) {
776 if (size < sizeof(uint32_t)) goto malformed;
778 serializable<FixedSizeData<uint32_t>> entryLength(
779 data, size, elf->getClass(), elf->getData());
780 if (!advance_buffer(&data, &size, sizeof(uint32_t))) goto malformed;
782 char* cursor = data;
783 size_t length = entryLength.value;
785 if (length == 0) {
786 continue;
789 if (size < sizeof(uint32_t)) goto malformed;
791 serializable<FixedSizeData<uint32_t>> id(data, size, elf->getClass(),
792 elf->getData());
793 if (!advance_buffer(&cursor, &length, sizeof(uint32_t))) goto malformed;
795 if (id.value == 0) {
796 // This is a Common Information Entry
797 if (length < 2) goto malformed;
798 // Reset LSDA and FDE encodings, and hasZ for subsequent FDEs.
799 LSDAencoding = DW_EH_PE_omit;
800 FDEencoding = DW_EH_PE_absptr;
801 hasZ = false;
802 // CIE version. Should only be 1 or 3.
803 char version = *cursor++;
804 length--;
805 if (version != 1 && version != 3) {
806 throw std::runtime_error("Unsupported eh_frame version");
808 // NUL terminated string.
809 const char* augmentationString = cursor;
810 size_t l = strnlen(augmentationString, length - 1);
811 if (l == length - 1) goto malformed;
812 if (!advance_buffer(&cursor, &length, l + 1)) goto malformed;
813 // Skip code alignment factor (LEB128)
814 if (!skip_LEB128(&cursor, &length)) goto malformed;
815 // Skip data alignment factor (LEB128)
816 if (!skip_LEB128(&cursor, &length)) goto malformed;
817 // Skip return address register (single byte in CIE version 1, LEB128
818 // in CIE version 3)
819 if (version == 1) {
820 if (!advance_buffer(&cursor, &length, 1)) goto malformed;
821 } else {
822 if (!skip_LEB128(&cursor, &length)) goto malformed;
824 // Past this, it's data driven by the contents of the augmentation string.
825 for (size_t i = 0; i < l; i++) {
826 if (!length) goto malformed;
827 switch (augmentationString[i]) {
828 case 'z':
829 if (!skip_LEB128(&cursor, &length)) goto malformed;
830 hasZ = true;
831 break;
832 case 'L':
833 LSDAencoding = *cursor++;
834 length--;
835 break;
836 case 'R':
837 FDEencoding = *cursor++;
838 length--;
839 break;
840 case 'P': {
841 unsigned char encoding = (unsigned char)*cursor++;
842 length--;
843 if (!adjust_eh_frame_pointer(&cursor, &length, encoding, eh_frame,
844 origAddr, elf))
845 goto malformed;
846 } break;
847 default:
848 goto malformed;
851 } else {
852 // This is a Frame Description Entry
853 // Starting address
854 if (!adjust_eh_frame_pointer(&cursor, &length, FDEencoding, eh_frame,
855 origAddr, elf))
856 goto malformed;
858 if (LSDAencoding != DW_EH_PE_omit) {
859 // Skip number of bytes, same size as the starting address.
860 if (!skip_eh_frame_pointer(&cursor, &length, FDEencoding))
861 goto malformed;
862 if (hasZ) {
863 if (!skip_LEB128(&cursor, &length)) goto malformed;
865 // pointer to the LSDA.
866 if (!adjust_eh_frame_pointer(&cursor, &length, LSDAencoding, eh_frame,
867 origAddr, elf))
868 goto malformed;
872 data += entryLength.value;
873 size -= entryLength.value;
875 return;
877 malformed:
878 throw std::runtime_error("malformed .eh_frame");
881 template <typename Rel_Type>
882 int do_relocation_section(Elf* elf, unsigned int rel_type,
883 unsigned int rel_type2, bool force) {
884 ElfDynamic_Section* dyn = elf->getDynSection();
885 if (dyn == nullptr) {
886 fprintf(stderr, "Couldn't find SHT_DYNAMIC section\n");
887 return -1;
890 ElfRel_Section<Rel_Type>* section =
891 (ElfRel_Section<Rel_Type>*)dyn->getSectionForType(Rel_Type::d_tag);
892 if (section == nullptr) {
893 fprintf(stderr, "No relocations\n");
894 return -1;
896 assert(section->getType() == Rel_Type::sh_type);
898 Elf64_Shdr relhack64_section = {0,
899 SHT_PROGBITS,
900 SHF_ALLOC,
902 (Elf64_Off)-1LL,
904 SHN_UNDEF,
906 Elf_Addr::size(elf->getClass()),
907 Elf_Addr::size(elf->getClass())};
908 Elf64_Shdr relhackcode64_section = {0,
909 SHT_PROGBITS,
910 SHF_ALLOC | SHF_EXECINSTR,
912 (Elf64_Off)-1LL,
914 SHN_UNDEF,
919 unsigned int entry_sz = Elf_Addr::size(elf->getClass());
921 // The injected code needs to be executed before any init code in the
922 // binary. There are three possible cases:
923 // - The binary has no init code at all. In this case, we will add a
924 // DT_INIT entry pointing to the injected code.
925 // - The binary has a DT_INIT entry. In this case, we will interpose:
926 // we change DT_INIT to point to the injected code, and have the
927 // injected code call the original DT_INIT entry point.
928 // - The binary has no DT_INIT entry, but has a DT_INIT_ARRAY. In this
929 // case, we interpose as well, by replacing the first entry in the
930 // array to point to the injected code, and have the injected code
931 // call the original first entry.
932 // The binary may have .ctors instead of DT_INIT_ARRAY, for its init
933 // functions, but this falls into the second case above, since .ctors
934 // are actually run by DT_INIT code.
935 ElfValue* value = dyn->getValueForType(DT_INIT);
936 unsigned int original_init = value ? value->getValue() : 0;
937 ElfSection* init_array = nullptr;
938 if (!value || !value->getValue()) {
939 value = dyn->getValueForType(DT_INIT_ARRAYSZ);
940 if (value && value->getValue() >= entry_sz)
941 init_array = dyn->getSectionForType(DT_INIT_ARRAY);
944 Elf_Shdr relhack_section(relhack64_section);
945 Elf_Shdr relhackcode_section(relhackcode64_section);
946 auto relhack_ptr = std::make_unique<ElfRelHack_Section>(relhack_section);
947 auto relhack = relhack_ptr.get();
949 ElfSymtab_Section* symtab = (ElfSymtab_Section*)section->getLink();
950 Elf_SymValue* sym = symtab->lookup("__cxa_pure_virtual");
952 std::vector<Rel_Type> new_rels;
953 std::vector<Rel_Type> init_array_relocs;
954 size_t init_array_insert = 0;
955 for (typename std::vector<Rel_Type>::iterator i = section->rels.begin();
956 i != section->rels.end(); ++i) {
957 // We don't need to keep R_*_NONE relocations
958 if (!ELF64_R_TYPE(i->r_info)) continue;
959 ElfLocation loc(i->r_offset, elf);
960 // __cxa_pure_virtual is a function used in vtables to point at pure
961 // virtual methods. The __cxa_pure_virtual function usually abort()s.
962 // These functions are however normally never called. In the case
963 // where they would, jumping to the null address instead of calling
964 // __cxa_pure_virtual is going to work just as well. So we can remove
965 // relocations for the __cxa_pure_virtual symbol and null out the
966 // content at the offset pointed by the relocation.
967 if (sym) {
968 if (sym->defined) {
969 // If we are statically linked to libstdc++, the
970 // __cxa_pure_virtual symbol is defined in our lib, and we
971 // have relative relocations (rel_type) for it.
972 if (ELF64_R_TYPE(i->r_info) == rel_type) {
973 Elf_Addr addr(loc.getBuffer(), entry_sz, elf->getClass(),
974 elf->getData());
975 if (addr.value == sym->value.getValue()) {
976 memset((char*)loc.getBuffer(), 0, entry_sz);
977 continue;
980 } else {
981 // If we are dynamically linked to libstdc++, the
982 // __cxa_pure_virtual symbol is undefined in our lib, and we
983 // have absolute relocations (rel_type2) for it.
984 if ((ELF64_R_TYPE(i->r_info) == rel_type2) &&
985 (sym == &symtab->syms[ELF64_R_SYM(i->r_info)])) {
986 memset((char*)loc.getBuffer(), 0, entry_sz);
987 continue;
991 // Keep track of the relocations associated with the init_array section.
992 if (init_array && i->r_offset >= init_array->getAddr() &&
993 i->r_offset < init_array->getAddr() + init_array->getSize()) {
994 init_array_relocs.push_back(*i);
995 init_array_insert = new_rels.size();
996 } else if (!(loc.getSection()->getFlags() & SHF_WRITE) ||
997 (ELF64_R_TYPE(i->r_info) != rel_type)) {
998 // Don't pack relocations happening in non writable sections.
999 // Our injected code is likely not to be allowed to write there.
1000 new_rels.push_back(*i);
1001 } else if (i->r_offset & 1) {
1002 // RELR packing doesn't support relocations at an odd address, but
1003 // there shouldn't be any.
1004 new_rels.push_back(*i);
1005 } else {
1006 // With Elf_Rel, the value pointed by the relocation offset is the addend.
1007 // With Elf_Rela, the addend is in the relocation entry, but the elfhacked
1008 // relocation info doesn't contain it. Elfhack relies on the value pointed
1009 // by the relocation offset to also contain the addend. Which is true with
1010 // BFD ld and gold, but not lld, which leaves that nulled out. So if that
1011 // value is nulled out, we update it to the addend.
1012 Elf_Addr addr(loc.getBuffer(), entry_sz, elf->getClass(), elf->getData());
1013 unsigned int addend = get_addend(&*i, elf);
1014 if (addr.value == 0) {
1015 addr.value = addend;
1016 addr.serialize(const_cast<char*>(loc.getBuffer()), entry_sz,
1017 elf->getClass(), elf->getData());
1018 } else if (addr.value != addend) {
1019 fprintf(stderr,
1020 "Relocation addend inconsistent with content. Skipping\n");
1021 return -1;
1023 relhack->push_back(i->r_offset);
1027 if (init_array) {
1028 // Some linkers create a DT_INIT_ARRAY section that, for all purposes,
1029 // is empty: it only contains 0x0 or 0xffffffff pointers with no
1030 // relocations. In some other cases, there can be null pointers with no
1031 // relocations in the middle of the section. Example: crtend_so.o in the
1032 // Android NDK contains a sized .init_array with a null pointer and no
1033 // relocation, which ends up in all Android libraries, and in some cases it
1034 // ends up in the middle of the final .init_array section. If we have such a
1035 // reusable slot at the beginning of .init_array, we just use it. It we have
1036 // one in the middle of .init_array, we slide its content to move the "hole"
1037 // at the beginning and use it there (we need our injected code to run
1038 // before any other). Otherwise, replace the first entry and keep the
1039 // original pointer.
1040 std::sort(init_array_relocs.begin(), init_array_relocs.end(),
1041 [](Rel_Type& a, Rel_Type& b) { return a.r_offset < b.r_offset; });
1042 size_t expected = init_array->getAddr();
1043 const size_t zero = 0;
1044 const size_t all = SIZE_MAX;
1045 const char* data = init_array->getData();
1046 size_t length = Elf_Addr::size(elf->getClass());
1047 size_t off = 0;
1048 for (; off < init_array_relocs.size(); off++) {
1049 auto& r = init_array_relocs[off];
1050 if (r.r_offset >= expected + length &&
1051 (memcmp(data + off * length, &zero, length) == 0 ||
1052 memcmp(data + off * length, &all, length) == 0)) {
1053 // We found a hole, move the preceding entries.
1054 while (off) {
1055 auto& p = init_array_relocs[--off];
1056 if (ELF64_R_TYPE(p.r_info) == rel_type) {
1057 unsigned int addend = get_addend(&p, elf);
1058 p.r_offset += length;
1059 set_relative_reloc(&p, elf, addend);
1060 } else {
1061 fprintf(stderr,
1062 "Unsupported relocation type in DT_INIT_ARRAY. Skipping\n");
1063 return -1;
1066 break;
1068 expected = r.r_offset + length;
1071 if (off == 0) {
1072 // We either found a hole above, and can now use the first entry,
1073 // or the init_array section is effectively empty (see further above)
1074 // and we also can use the first entry.
1075 // Either way, code further below will take care of actually setting
1076 // the right r_info and r_added for the relocation.
1077 Rel_Type rel;
1078 rel.r_offset = init_array->getAddr();
1079 init_array_relocs.insert(init_array_relocs.begin(), rel);
1080 } else {
1081 // Use relocated value of DT_INIT_ARRAY's first entry for the
1082 // function to be called by the injected code.
1083 auto& rel = init_array_relocs[0];
1084 unsigned int addend = get_addend(&rel, elf);
1085 if (ELF64_R_TYPE(rel.r_info) == rel_type) {
1086 original_init = addend;
1087 } else if (ELF64_R_TYPE(rel.r_info) == rel_type2) {
1088 ElfSymtab_Section* symtab = (ElfSymtab_Section*)section->getLink();
1089 original_init =
1090 symtab->syms[ELF64_R_SYM(rel.r_info)].value.getValue() + addend;
1091 } else {
1092 fprintf(stderr,
1093 "Unsupported relocation type for DT_INIT_ARRAY's first entry. "
1094 "Skipping\n");
1095 return -1;
1099 new_rels.insert(std::next(new_rels.begin(), init_array_insert),
1100 init_array_relocs.begin(), init_array_relocs.end());
1103 unsigned int mprotect_cb = 0;
1104 unsigned int sysconf_cb = 0;
1105 // If there is a relro segment, our injected code will run after the linker
1106 // sets the corresponding pages read-only. We need to make our code change
1107 // that to read-write before applying relocations, which means it needs to
1108 // call mprotect. To do that, we need to find a reference to the mprotect
1109 // symbol. In case the library already has one, we use that, but otherwise, we
1110 // add the symbol. Then the injected code needs to be able to call the
1111 // corresponding function, which means it needs access to a pointer to it. We
1112 // get such a pointer by making the linker apply a relocation for the symbol
1113 // at an address our code can read. The problem here is that there is not much
1114 // relocated space where we can put such a pointer, so we abuse the bss
1115 // section temporarily (it will be restored to a null value before any code
1116 // can actually use it)
1117 if (elf->getSegmentByType(PT_GNU_RELRO)) {
1118 ElfSection* gnu_versym = dyn->getSectionForType(DT_VERSYM);
1119 auto lookup = [&symtab, &gnu_versym](const char* symbol) {
1120 Elf_SymValue* sym_value = symtab->lookup(symbol, STT(FUNC));
1121 if (!sym_value) {
1122 symtab->syms.emplace_back();
1123 sym_value = &symtab->syms.back();
1124 symtab->grow(symtab->syms.size() * symtab->getEntSize());
1125 sym_value->name =
1126 ((ElfStrtab_Section*)symtab->getLink())->getStr(symbol);
1127 sym_value->info = ELF64_ST_INFO(STB_GLOBAL, STT_FUNC);
1128 sym_value->other = STV_DEFAULT;
1129 new (&sym_value->value) ElfLocation(nullptr, 0, ElfLocation::ABSOLUTE);
1130 sym_value->size = 0;
1131 sym_value->defined = false;
1133 // The DT_VERSYM data (in the .gnu.version section) has the same number
1134 // of entries as the symbols table. Since we added one entry there, we
1135 // need to add one entry here. Zeroes in the extra data means no version
1136 // for that symbol, which is the simplest thing to do.
1137 if (gnu_versym) {
1138 gnu_versym->grow(gnu_versym->getSize() + gnu_versym->getEntSize());
1141 return sym_value;
1144 Elf_SymValue* mprotect = lookup("mprotect");
1145 Elf_SymValue* sysconf = lookup("sysconf");
1147 // Add relocations for the mprotect and sysconf symbols.
1148 auto add_relocation_to = [&new_rels, &symtab, rel_type2](
1149 Elf_SymValue* symbol, unsigned int location) {
1150 new_rels.emplace_back();
1151 Rel_Type& rel = new_rels.back();
1152 memset(&rel, 0, sizeof(rel));
1153 rel.r_info = ELF64_R_INFO(
1154 std::distance(symtab->syms.begin(),
1155 std::vector<Elf_SymValue>::iterator(symbol)),
1156 rel_type2);
1157 rel.r_offset = location;
1158 return location;
1161 // Find the beginning of the bss section, and use an aligned location in
1162 // there for the relocation.
1163 for (ElfSection* s = elf->getSection(1); s != nullptr; s = s->getNext()) {
1164 if (s->getType() != SHT_NOBITS ||
1165 (s->getFlags() & (SHF_TLS | SHF_WRITE)) != SHF_WRITE) {
1166 continue;
1168 size_t ptr_size = Elf_Addr::size(elf->getClass());
1169 size_t usable_start = (s->getAddr() + ptr_size - 1) & ~(ptr_size - 1);
1170 size_t usable_end = (s->getAddr() + s->getSize()) & ~(ptr_size - 1);
1171 if (usable_end - usable_start >= 2 * ptr_size) {
1172 mprotect_cb = add_relocation_to(mprotect, usable_start);
1173 sysconf_cb = add_relocation_to(sysconf, usable_start + ptr_size);
1174 break;
1178 if (mprotect_cb == 0 || sysconf_cb == 0) {
1179 fprintf(stderr, "Couldn't find .bss. Skipping\n");
1180 return -1;
1184 size_t old_size = section->getSize();
1186 section->rels.assign(new_rels.begin(), new_rels.end());
1187 section->shrink(new_rels.size() * section->getEntSize());
1189 auto relhackcode_ptr = std::make_unique<ElfRelHackCode_Section>(
1190 relhackcode_section, *elf, *relhack, original_init, mprotect_cb,
1191 sysconf_cb);
1192 auto relhackcode = relhackcode_ptr.get();
1193 // Find the first executable section, and insert the relhack code before
1194 // that. The relhack data is inserted between .rel.dyn and .rel.plt.
1195 ElfSection* first_executable = nullptr;
1196 for (ElfSection* s = elf->getSection(1); s != nullptr; s = s->getNext()) {
1197 if (s->getFlags() & SHF_EXECINSTR) {
1198 first_executable = s;
1199 break;
1203 if (!first_executable) {
1204 fprintf(stderr, "Couldn't find executable section. Skipping\n");
1205 return -1;
1208 // Once the pointers for relhack, relhackcode, and init are inserted,
1209 // their ownership is transferred to the Elf object, which will free
1210 // them when itself is freed. Hence the .release() calls here (and
1211 // the init.release() call later on). Please note that the raw
1212 // pointers will continue to be used after .release(), which is why
1213 // we are caching them (since .release() will end up setting the
1214 // smart pointer's internal raw pointer to nullptr).
1216 relhack->insertBefore(section);
1217 relhack_ptr.release();
1219 relhackcode->insertBefore(first_executable);
1220 relhackcode_ptr.release();
1222 // Don't try further if we can't gain from the relocation section size change.
1223 // We account for the fact we're going to split the PT_LOAD before the
1224 // injected code section, so the overhead of the page alignment for section
1225 // needs to be accounted for.
1226 size_t align = first_executable->getSegmentByType(PT_LOAD)->getAlign();
1227 size_t new_size = relhack->getSize() + section->getSize() +
1228 relhackcode->getSize() +
1229 (relhackcode->getAddr() & (align - 1));
1230 if (!force && (new_size >= old_size || old_size - new_size < align)) {
1231 fprintf(stderr, "No gain. Skipping\n");
1232 return -1;
1235 // .eh_frame/.eh_frame_hdr may be between the relocation sections and the
1236 // executable sections. When that happens, we may end up creating a separate
1237 // PT_LOAD for just both of them because they are not considered relocatable.
1238 // But they are, in fact, kind of relocatable, albeit with some manual work.
1239 // Which we'll do here.
1240 ElfSegment* eh_frame_segment = elf->getSegmentByType(PT_GNU_EH_FRAME);
1241 ElfSection* eh_frame_hdr =
1242 eh_frame_segment ? eh_frame_segment->getFirstSection() : nullptr;
1243 // The .eh_frame section usually follows the eh_frame_hdr section.
1244 ElfSection* eh_frame = eh_frame_hdr ? eh_frame_hdr->getNext() : nullptr;
1245 ElfSection* first = eh_frame_hdr;
1246 ElfSection* second = eh_frame;
1247 if (eh_frame && strcmp(eh_frame->getName(), ".eh_frame")) {
1248 // But sometimes it appears *before* the eh_frame_hdr section.
1249 eh_frame = eh_frame_hdr->getPrevious();
1250 first = eh_frame;
1251 second = eh_frame_hdr;
1253 if (eh_frame_hdr && (!eh_frame || strcmp(eh_frame->getName(), ".eh_frame"))) {
1254 throw std::runtime_error(
1255 "Expected to find an .eh_frame section adjacent to .eh_frame_hdr");
1257 if (eh_frame && first->getAddr() > relhack->getAddr() &&
1258 second->getAddr() < first_executable->getAddr()) {
1259 // The distance between both sections needs to be preserved because
1260 // eh_frame_hdr contains relative offsets to eh_frame. Well, they could be
1261 // relocated too, but it's not worth the effort for the few number of bytes
1262 // this would save.
1263 Elf64_Off distance = second->getAddr() - first->getAddr();
1264 Elf64_Addr origAddr = eh_frame->getAddr();
1265 ElfSection* previous = first->getPrevious();
1266 first->getShdr().sh_addr = (previous->getAddr() + previous->getSize() +
1267 first->getAddrAlign() - 1) &
1268 ~(first->getAddrAlign() - 1);
1269 second->getShdr().sh_addr =
1270 (first->getAddr() + std::min(first->getSize(), distance) +
1271 second->getAddrAlign() - 1) &
1272 ~(second->getAddrAlign() - 1);
1273 // Re-adjust to keep the original distance.
1274 // If the first section has a smaller alignment requirement than the second,
1275 // the second will be farther away, so we need to adjust the first.
1276 // If the second section has a smaller alignment requirement than the first,
1277 // it will already be at the right distance.
1278 first->getShdr().sh_addr = second->getAddr() - distance;
1279 assert(distance == second->getAddr() - first->getAddr());
1280 first->markDirty();
1281 adjust_eh_frame(eh_frame, origAddr, elf);
1284 // Adjust PT_LOAD segments
1285 for (ElfSegment* segment = elf->getSegmentByType(PT_LOAD); segment;
1286 segment = elf->getSegmentByType(PT_LOAD, segment)) {
1287 maybe_split_segment(elf, segment);
1290 // Ensure Elf sections will be at their final location.
1291 elf->normalize();
1292 auto init =
1293 std::make_unique<ElfLocation>(relhackcode, relhackcode->getEntryPoint());
1294 if (init_array) {
1295 // Adjust the first DT_INIT_ARRAY entry to point at the injected code
1296 // by transforming its relocation into a relative one pointing to the
1297 // address of the injected code.
1298 Rel_Type* rel = &section->rels[init_array_insert];
1299 rel->r_info = ELF64_R_INFO(0, rel_type); // Set as a relative relocation
1300 set_relative_reloc(rel, elf, init->getValue());
1301 } else {
1302 if (dyn->setValueForType(DT_INIT, init.get())) {
1303 init.release();
1304 } else {
1305 fprintf(stderr, "Can't grow .dynamic section to set DT_INIT. Skipping\n");
1306 return -1;
1310 // TODO: adjust the value according to the remaining number of relative
1311 // relocations
1312 if (dyn->getValueForType(Rel_Type::d_tag_count))
1313 dyn->setValueForType(Rel_Type::d_tag_count, new ElfPlainValue(0));
1315 return 0;
1318 static inline int backup_file(const char* name) {
1319 std::string fname(name);
1320 fname += ".bak";
1321 return rename(name, fname.c_str());
1324 void do_file(const char* name, bool backup = false, bool force = false) {
1325 std::ifstream file(name, std::ios::in | std::ios::binary);
1326 Elf elf(file);
1327 unsigned int size = elf.getSize();
1328 fprintf(stderr, "%s: ", name);
1329 if (elf.getType() != ET_DYN) {
1330 fprintf(stderr, "Not a shared object. Skipping\n");
1331 return;
1334 for (ElfSection* section = elf.getSection(1); section != nullptr;
1335 section = section->getNext()) {
1336 if (section->getName() &&
1337 (strncmp(section->getName(), ".elfhack.", 9) == 0)) {
1338 fprintf(stderr, "Already elfhacked. Skipping\n");
1339 return;
1343 int exit = -1;
1344 switch (elf.getMachine()) {
1345 case EM_386:
1346 exit =
1347 do_relocation_section<Elf_Rel>(&elf, R_386_RELATIVE, R_386_32, force);
1348 break;
1349 case EM_X86_64:
1350 exit = do_relocation_section<Elf_Rela>(&elf, R_X86_64_RELATIVE,
1351 R_X86_64_64, force);
1352 break;
1353 case EM_ARM:
1354 exit = do_relocation_section<Elf_Rel>(&elf, R_ARM_RELATIVE, R_ARM_ABS32,
1355 force);
1356 break;
1357 case EM_AARCH64:
1358 exit = do_relocation_section<Elf_Rela>(&elf, R_AARCH64_RELATIVE,
1359 R_AARCH64_ABS64, force);
1360 break;
1361 default:
1362 throw std::runtime_error("unsupported architecture");
1364 if (exit == 0) {
1365 if (!force && (elf.getSize() >= size)) {
1366 fprintf(stderr, "No gain. Skipping\n");
1367 } else if (backup && backup_file(name) != 0) {
1368 fprintf(stderr, "Couln't create backup file\n");
1369 } else {
1370 std::ofstream ofile(name,
1371 std::ios::out | std::ios::binary | std::ios::trunc);
1372 elf.write(ofile);
1373 fprintf(stderr, "Reduced by %d bytes\n", size - elf.getSize());
1378 void undo_file(const char* name, bool backup = false) {
1379 std::ifstream file(name, std::ios::in | std::ios::binary);
1380 Elf elf(file);
1381 unsigned int size = elf.getSize();
1382 fprintf(stderr, "%s: ", name);
1383 if (elf.getType() != ET_DYN) {
1384 fprintf(stderr, "Not a shared object. Skipping\n");
1385 return;
1388 ElfSection *data = nullptr, *text = nullptr;
1389 for (ElfSection* section = elf.getSection(1); section != nullptr;
1390 section = section->getNext()) {
1391 if (section->getName() && (strcmp(section->getName(), elfhack_data) == 0))
1392 data = section;
1393 if (section->getName() && (strcmp(section->getName(), elfhack_text) == 0))
1394 text = section;
1397 if (!data || !text) {
1398 fprintf(stderr, "Not elfhacked. Skipping\n");
1399 return;
1402 // When both elfhack sections are in the same segment, try to merge
1403 // the segment that contains them both and the following segment.
1404 // When the elfhack sections are in separate segments, try to merge
1405 // those segments.
1406 ElfSegment* first = data->getSegmentByType(PT_LOAD);
1407 ElfSegment* second = text->getSegmentByType(PT_LOAD);
1408 if (first == second) {
1409 second = elf.getSegmentByType(PT_LOAD, first);
1412 // Only merge the segments when their flags match.
1413 if (second->getFlags() != first->getFlags()) {
1414 fprintf(stderr, "Couldn't merge PT_LOAD segments. Skipping\n");
1415 return;
1417 // Move sections from the second PT_LOAD to the first, and remove the
1418 // second PT_LOAD segment.
1419 for (std::list<ElfSection*>::iterator section = second->begin();
1420 section != second->end(); ++section)
1421 first->addSection(*section);
1423 elf.removeSegment(second);
1424 elf.normalize();
1426 if (backup && backup_file(name) != 0) {
1427 fprintf(stderr, "Couln't create backup file\n");
1428 } else {
1429 std::ofstream ofile(name,
1430 std::ios::out | std::ios::binary | std::ios::trunc);
1431 elf.write(ofile);
1432 fprintf(stderr, "Grown by %d bytes\n", elf.getSize() - size);
1436 int main(int argc, char* argv[]) {
1437 int arg;
1438 bool backup = false;
1439 bool force = false;
1440 bool revert = false;
1441 char* lastSlash = rindex(argv[0], '/');
1442 if (lastSlash != nullptr) rundir = strndup(argv[0], lastSlash - argv[0]);
1443 for (arg = 1; arg < argc; arg++) {
1444 if (strcmp(argv[arg], "-f") == 0)
1445 force = true;
1446 else if (strcmp(argv[arg], "-b") == 0)
1447 backup = true;
1448 else if (strcmp(argv[arg], "-r") == 0)
1449 revert = true;
1450 else if (revert) {
1451 undo_file(argv[arg], backup);
1452 } else
1453 do_file(argv[arg], backup, force);
1456 free(rundir);
1457 return 0;