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 GElf_Xword elfu_mInsertAfter(ElfuElf *me, GElf_Off off, GElf_Xword size)
132 /* Move SHDRs and PHDRs */
133 if (me->ehdr.e_shoff >= off) {
134 me->ehdr.e_shoff += size;
137 if (me->ehdr.e_phoff >= off) {
138 me->ehdr.e_phoff += size;
141 /* Patch PHDRs to include new data */
142 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
143 GElf_Off end = mp->phdr.p_offset + mp->phdr.p_filesz;
145 if (mp->phdr.p_offset >= off) {
146 /* Insertion before PHDR's content, so it's shifted. */
147 mp->phdr.p_offset += size;
149 /* It may also need to be remapped. See second pass below. */
151 /* mp->phdr.p_offset < off */
154 /* Insertion in the middle of PHDR, so let it span the new data */
155 mp->phdr.p_filesz += size;
156 mp->phdr.p_memsz += size;
158 /* Insertion after PHDR's content. Nothing to do. */
163 /* For each LOAD header, find clashing headers that need to be
164 remapped to lower memory areas.
166 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
167 if (mp->phdr.p_type == PT_LOAD) {
170 CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
171 if (mp2->phdr.p_type != PT_LOAD
172 && mp2->phdr.p_offset + mp2->phdr.p_filesz > off) {
173 /* The PHDR now ends in the file after the injection site */
174 GElf_Off vend1 = mp->phdr.p_vaddr + mp->phdr.p_memsz;
175 GElf_Off pend1 = mp->phdr.p_paddr + mp->phdr.p_memsz;
176 GElf_Off vend2 = mp2->phdr.p_vaddr + mp2->phdr.p_memsz;
177 GElf_Off pend2 = mp2->phdr.p_paddr + mp2->phdr.p_memsz;
179 /* If mp and mp2 now overlap in memory */
180 if ((mp2->phdr.p_vaddr < vend1 && vend2 > mp->phdr.p_vaddr)
181 || (mp2->phdr.p_paddr < pend1 && pend2 > mp->phdr.p_paddr)) {
182 /* Move mp2 up in memory, as mp has been resized.
183 Maintaining the relative offset between them is the best
184 guess at maintaining consistency.
187 mp2->phdr.p_vaddr += size;
188 mp2->phdr.p_paddr += size;
195 /* Move the sections themselves */
196 CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
197 if (ms->shdr.sh_offset >= off) {
198 ms->shdr.sh_offset += size;
200 /* If this was in a LOAD segment, it has been adjusted there
201 and this synchronises it.
202 If not, it doesn't matter anyway.
204 ms->shdr.sh_addr += size;