2 * Copyright (c) 2016 Kai Wang
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/param.h>
36 ELFTC_VCSID("$Id: libpe_section.c 3446 2016-05-03 01:31:17Z emaste $");
39 libpe_alloc_scn(PE *pe)
43 if ((ps = calloc(1, sizeof(PE_Scn))) == NULL) {
47 STAILQ_INIT(&ps->ps_b);
54 libpe_release_scn(PE_Scn *ps)
63 STAILQ_REMOVE(&pe->pe_scn, ps, _PE_Scn, ps_next);
65 STAILQ_FOREACH_SAFE(sb, &ps->ps_b, sb_next, _sb)
66 libpe_release_buffer(sb);
72 cmp_scn(PE_Scn *a, PE_Scn *b)
75 if (a->ps_sh.sh_addr < b->ps_sh.sh_addr)
77 else if (a->ps_sh.sh_addr == b->ps_sh.sh_addr)
87 if (STAILQ_EMPTY(&pe->pe_scn))
90 /* Sort the list of Scn by RVA in ascending order. */
91 STAILQ_SORT(&pe->pe_scn, _PE_Scn, ps_next, cmp_scn);
95 libpe_parse_section_headers(PE *pe)
97 char tmp[sizeof(PE_SecHdr)], *hdr;
104 assert(pe->pe_ch != NULL);
106 for (i = 0; (uint16_t) i < pe->pe_ch->ch_nsec; i++) {
107 if (read(pe->pe_fd, tmp, sizeof(PE_SecHdr)) !=
108 (ssize_t) sizeof(PE_SecHdr)) {
109 pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;
113 if ((ps = libpe_alloc_scn(pe)) == NULL)
115 STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
116 ps->ps_ndx = ++pe->pe_nscn; /* Setion index is 1-based */
120 * Note that the section name won't be NUL-terminated if
121 * its length happens to be 8.
123 memcpy(sh->sh_name, tmp, sizeof(sh->sh_name));
125 PE_READ32(hdr, sh->sh_virtsize);
126 PE_READ32(hdr, sh->sh_addr);
127 PE_READ32(hdr, sh->sh_rawsize);
128 PE_READ32(hdr, sh->sh_rawptr);
129 PE_READ32(hdr, sh->sh_relocptr);
130 PE_READ32(hdr, sh->sh_lineptr);
131 PE_READ16(hdr, sh->sh_nreloc);
132 PE_READ16(hdr, sh->sh_nline);
133 PE_READ32(hdr, sh->sh_char);
137 * For all the data directories that don't belong to any section,
138 * we create pseudo sections for them to make layout easier.
141 if (dd != NULL && dd->dd_total > 0) {
142 for (i = 0; (uint32_t) i < pe->pe_dd->dd_total; i++) {
143 if (dd->dd_e[i].de_size == 0)
146 STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
148 if (dd->dd_e[i].de_addr >= sh->sh_addr &&
149 dd->dd_e[i].de_addr + dd->dd_e[i].de_size <=
150 sh->sh_addr + sh->sh_virtsize) {
158 if ((ps = libpe_alloc_scn(pe)) == NULL)
160 STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
161 ps->ps_ndx = 0xFFFF0000U | i;
163 sh->sh_rawptr = dd->dd_e[i].de_addr; /* FIXME */
164 sh->sh_rawsize = dd->dd_e[i].de_size;
169 * Also consider the COFF symbol table as a pseudo section.
172 if (ch->ch_nsym > 0) {
173 if ((ps = libpe_alloc_scn(pe)) == NULL)
175 STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
176 ps->ps_ndx = 0xFFFFFFFFU;
178 sh->sh_rawptr = ch->ch_symptr;
179 sh->sh_rawsize = ch->ch_nsym * PE_SYM_ENTRY_SIZE;
180 pe->pe_nsym = ch->ch_nsym;
183 /* PE file headers initialization is complete if we reach here. */
188 libpe_load_section(PE *pe, PE_Scn *ps)
195 assert(pe != NULL && ps != NULL);
196 assert((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0);
200 /* Allocate a PE_SecBuf struct without buffer for empty sections. */
201 if (sh->sh_rawsize == 0) {
202 (void) libpe_alloc_buffer(ps, 0);
203 ps->ps_flags |= LIBPE_F_LOAD_SECTION;
207 if ((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0) {
208 if (lseek(pe->pe_fd, (off_t) sh->sh_rawptr, SEEK_SET) < 0) {
214 if ((sb = libpe_alloc_buffer(ps, sh->sh_rawsize)) == NULL)
217 if (read(pe->pe_fd, sb->sb_pb.pb_buf, sh->sh_rawsize) !=
218 (ssize_t) sh->sh_rawsize) {
223 if (ps->ps_ndx == 0xFFFFFFFFU) {
225 * Index 0xFFFFFFFF indicates this section is a pseudo
226 * section that contains the COFF symbol table. We should
227 * read in the string table right after it.
229 if (read(pe->pe_fd, tmp, sizeof(tmp)) !=
230 (ssize_t) sizeof(tmp)) {
237 * The minimum value for the size field is 4, which indicates
238 * there is no string table.
242 if ((sb = libpe_alloc_buffer(ps, sz)) == NULL)
244 if (read(pe->pe_fd, sb->sb_pb.pb_buf, sz) !=
252 ps->ps_flags |= LIBPE_F_LOAD_SECTION;
258 libpe_load_all_sections(PE *pe)
266 /* Calculate the current offset into the file. */
268 if (pe->pe_dh != NULL)
269 off += pe->pe_dh->dh_lfanew + 4;
270 if (pe->pe_ch != NULL)
271 off += sizeof(PE_CoffHdr) + pe->pe_ch->ch_optsize;
273 STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
274 if (ps->ps_flags & LIBPE_F_LOAD_SECTION)
279 * For special files, we consume the padding in between
280 * and advance to the section offset.
282 if (pe->pe_flags & LIBPE_F_SPECIAL_FILE) {
283 /* Can't go backwards. */
284 if (off > sh->sh_rawptr) {
288 if (off < sh->sh_rawptr) {
289 r = sh->sh_rawptr - off;
290 for (; r > 0; r -= s) {
291 s = r > sizeof(tmp) ? sizeof(tmp) : r;
292 if (read(pe->pe_fd, tmp, s) !=
301 /* Load the section content. */
302 if (libpe_load_section(pe, ps) < 0)
310 libpe_resync_sections(PE *pe, off_t off)
316 /* Firstly, sort all sections by their file offsets. */
319 /* Count the number of sections. */
321 STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
322 if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
324 if (ps->ps_ndx & 0xFFFF0000U)
331 * Calculate the file offset for the first section. (`off' is
332 * currently pointing to the COFF header.)
334 off += sizeof(PE_CoffHdr);
335 if (pe->pe_ch != NULL && pe->pe_ch->ch_optsize > 0)
336 off += pe->pe_ch->ch_optsize;
338 switch (pe->pe_obj) {
340 off += PE_COFF_OPT_SIZE_32;
343 off += PE_COFF_OPT_SIZE_32P;
350 off += nsec * sizeof(PE_SecHdr);
353 * Determine the file alignment for sections.
355 if (pe->pe_oh != NULL && pe->pe_oh->oh_filealign > 0)
356 falign = pe->pe_oh->oh_filealign;
359 * Use the default file alignment defined by the
360 * PE/COFF specification.
362 if (pe->pe_obj == PE_O_COFF)
369 * Step through each section (and pseduo section) and verify
370 * alignment constraint and overlapping, make adjustment if need.
373 STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
374 if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
379 if (sh->sh_addr + sh->sh_virtsize > pe->pe_rvamax)
380 pe->pe_rvamax = sh->sh_addr + sh->sh_virtsize;
382 if (ps->ps_ndx & 0xFFFF0000U)
385 ps->ps_falign = falign;
387 off = roundup(off, ps->ps_falign);
389 if (off != sh->sh_rawptr)
390 ps->ps_flags |= PE_F_DIRTY;
392 if (ps->ps_flags & PE_F_DIRTY) {
393 if ((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0) {
394 if (libpe_load_section(pe, ps) < 0)
397 sh->sh_rawsize = libpe_resync_buffers(ps);
401 * Sections only contains uninitialized data should set
402 * PointerToRawData to zero according to the PE/COFF
405 if (sh->sh_rawsize == 0)
410 off += sh->sh_rawsize;
417 libpe_write_section_headers(PE *pe, off_t off)
419 char tmp[sizeof(PE_SecHdr)], *hdr;
423 if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER || pe->pe_nscn == 0)
426 if ((pe->pe_flags & LIBPE_F_DIRTY_SEC_HEADER) == 0) {
427 off += sizeof(PE_SecHdr) * pe->pe_ch->ch_nsec;
431 STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
432 if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
434 if (ps->ps_ndx & 0xFFFF0000U)
436 if ((pe->pe_flags & LIBPE_F_DIRTY_SEC_HEADER) == 0 &&
437 (ps->ps_flags & PE_F_DIRTY) == 0)
442 memcpy(tmp, sh->sh_name, sizeof(sh->sh_name));
444 PE_WRITE32(hdr, sh->sh_virtsize);
445 PE_WRITE32(hdr, sh->sh_addr);
446 PE_WRITE32(hdr, sh->sh_rawsize);
447 PE_WRITE32(hdr, sh->sh_rawptr);
448 PE_WRITE32(hdr, sh->sh_relocptr);
449 PE_WRITE32(hdr, sh->sh_lineptr);
450 PE_WRITE16(hdr, sh->sh_nreloc);
451 PE_WRITE16(hdr, sh->sh_nline);
452 PE_WRITE32(hdr, sh->sh_char);
454 if (write(pe->pe_fd, tmp, sizeof(PE_SecHdr)) !=
455 (ssize_t) sizeof(PE_SecHdr)) {
461 off += sizeof(PE_SecHdr);
468 libpe_write_sections(PE *pe, off_t off)
473 if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER)
476 STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
479 if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
482 /* Skip empty sections. */
483 if (sh->sh_rawptr == 0 || sh->sh_rawsize == 0)
487 * Padding between sections. (padding always written
488 * in case the the section headers or sections are
491 assert(off <= sh->sh_rawptr);
492 if (off < sh->sh_rawptr)
493 libpe_pad(pe, sh->sh_rawptr - off);
495 if ((ps->ps_flags & PE_F_DIRTY) == 0) {
496 assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
498 (off_t) (sh->sh_rawptr + sh->sh_rawsize),
503 off = sh->sh_rawptr + sh->sh_rawsize;
509 if (libpe_write_buffers(ps) < 0)
512 off += sh->sh_rawsize;
514 ps->ps_flags &= ~PE_F_DIRTY;