3 #include <libelf/gelf.h>
4 #include <libelfu/libelfu.h>
7 // TODO: Take p_align into account
12 * Insert space at a given position in the file by moving everything
13 * after it towards the end of the file, and everything before it
14 * towards lower memory regions where it is mapped.
16 * off must not be in the middle of any data structure, such as
17 * PHDRs, SHDRs, or sections. Behaviour is undefined if it is.
19 * PHDRs will be patched such that everything AFTER off is mapped to
20 * the same address in memory, and everything BEFORE it is shifted to
21 * lower addresses, making space for the new data in-between.
23 GElf_Xword elfu_mInsertBefore(ElfuElf *me, GElf_Off off, GElf_Xword size)
30 /* Move SHDRs and PHDRs */
31 if (me->ehdr.e_shoff >= off) {
32 me->ehdr.e_shoff += size;
35 if (me->ehdr.e_phoff >= off) {
36 me->ehdr.e_phoff += size;
39 /* Patch PHDRs to include new data */
40 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
41 GElf_Off end = mp->phdr.p_offset + mp->phdr.p_filesz;
43 if (mp->phdr.p_offset >= off) {
44 /* Insertion before PHDR's content, so it's just shifted */
45 mp->phdr.p_offset += size;
47 /* mp->phdr.p_offset < off */
50 /* Insertion in the middle of PHDR, so let it span the new data */
51 mp->phdr.p_filesz += size;
52 mp->phdr.p_memsz += size;
53 mp->phdr.p_vaddr -= size;
54 mp->phdr.p_paddr -= size;
56 /* Insertion after PHDR's content, so it may need to be
57 remapped. This will happen in a second pass.
63 /* For each LOAD header, find clashing headers that need to be
64 remapped to lower memory areas.
66 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
67 if (mp->phdr.p_type == PT_LOAD) {
70 CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
71 if (mp2->phdr.p_type != PT_LOAD
72 && mp2->phdr.p_offset + mp2->phdr.p_filesz <= off) {
73 /* The PHDR ends in the file before the injection site */
74 GElf_Off vend1 = mp->phdr.p_vaddr + mp->phdr.p_memsz;
75 GElf_Off pend1 = mp->phdr.p_paddr + mp->phdr.p_memsz;
76 GElf_Off vend2 = mp2->phdr.p_vaddr + mp2->phdr.p_memsz;
77 GElf_Off pend2 = mp2->phdr.p_paddr + mp2->phdr.p_memsz;
79 /* If mp and mp2 now overlap in memory */
80 if ((mp2->phdr.p_vaddr < vend1 && vend2 > mp->phdr.p_vaddr)
81 || (mp2->phdr.p_paddr < pend1 && pend2 > mp->phdr.p_paddr)) {
82 /* Move mp2 down in memory, as mp has been resized.
83 Maintaining the relative offset between them is the best
84 guess at maintaining consistency.
86 mp2->phdr.p_vaddr -= size;
87 mp2->phdr.p_paddr -= size;
94 /* Move the sections themselves */
95 CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
96 if (ms->shdr.sh_offset >= off) {
97 ms->shdr.sh_offset += size;
101 /* If this was in a LOAD segment, it has been adjusted there
102 and this synchronises it.
103 If not, it doesn't matter anyway.
105 ms->shdr.sh_addr -= size;
115 * Insert space at a given position in the file by moving everything
116 * after it towards the end of the file, and towards higher memory
117 * regions where it is mapped.
119 * off must not be in the middle of any data structure, such as
120 * PHDRs, SHDRs, or sections. Behaviour is undefined if it is.
122 * PHDRs will be patched such that everything AFTER off is shifted to
123 * higher addresses, making space for the new data in-between.
125 * CAUTION: This also moves NOBITS sections. If such are present,
126 * use mExpandNobits() first and then inject at the end of
127 * the expansion site.
129 GElf_Xword elfu_mInsertAfter(ElfuElf *me, GElf_Off off, GElf_Xword size)
136 /* Move SHDRs and PHDRs */
137 if (me->ehdr.e_shoff >= off) {
138 me->ehdr.e_shoff += size;
141 if (me->ehdr.e_phoff >= off) {
142 me->ehdr.e_phoff += size;
145 /* Patch PHDRs to include new data */
146 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
147 GElf_Off end = mp->phdr.p_offset + mp->phdr.p_filesz;
149 if (mp->phdr.p_offset >= off) {
150 /* Insertion before PHDR's content, so it's shifted. */
151 mp->phdr.p_offset += size;
153 /* It may also need to be remapped. See second pass below. */
155 /* mp->phdr.p_offset < off */
158 /* Insertion in the middle of PHDR, so let it span the new data */
159 mp->phdr.p_filesz += size;
160 mp->phdr.p_memsz += size;
162 /* Insertion after PHDR's content. Nothing to do. */
167 /* For each LOAD header, find clashing headers that need to be
168 remapped to higher memory areas.
170 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
171 if (mp->phdr.p_type == PT_LOAD) {
174 CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
175 if (mp2->phdr.p_type != PT_LOAD
176 && mp2->phdr.p_offset + mp2->phdr.p_filesz > off) {
177 /* The PHDR now ends in the file after the injection site */
178 GElf_Off vend1 = mp->phdr.p_vaddr + mp->phdr.p_memsz;
179 GElf_Off pend1 = mp->phdr.p_paddr + mp->phdr.p_memsz;
180 GElf_Off vend2 = mp2->phdr.p_vaddr + mp2->phdr.p_memsz;
181 GElf_Off pend2 = mp2->phdr.p_paddr + mp2->phdr.p_memsz;
183 /* If mp and mp2 now overlap in memory */
184 if ((mp2->phdr.p_vaddr < vend1 && vend2 > mp->phdr.p_vaddr)
185 || (mp2->phdr.p_paddr < pend1 && pend2 > mp->phdr.p_paddr)) {
186 /* Move mp2 up in memory, as mp has been resized.
187 Maintaining the relative offset between them is the best
188 guess at maintaining consistency.
191 mp2->phdr.p_vaddr += size;
192 mp2->phdr.p_paddr += size;
199 /* Move the sections themselves */
200 CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
201 if (ms->shdr.sh_offset >= off) {
202 ms->shdr.sh_offset += size;
204 /* If this was in a LOAD segment, it has been adjusted there
205 and this synchronises it.
206 If not, it doesn't matter anyway.
208 ms->shdr.sh_addr += size;