1839529caSEd Maste /*-
2839529caSEd Maste * Copyright (c) 2016 Kai Wang
3839529caSEd Maste * All rights reserved.
4839529caSEd Maste *
5839529caSEd Maste * Redistribution and use in source and binary forms, with or without
6839529caSEd Maste * modification, are permitted provided that the following conditions
7839529caSEd Maste * are met:
8839529caSEd Maste * 1. Redistributions of source code must retain the above copyright
9839529caSEd Maste * notice, this list of conditions and the following disclaimer.
10839529caSEd Maste * 2. Redistributions in binary form must reproduce the above copyright
11839529caSEd Maste * notice, this list of conditions and the following disclaimer in the
12839529caSEd Maste * documentation and/or other materials provided with the distribution.
13839529caSEd Maste *
14839529caSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15839529caSEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16839529caSEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17839529caSEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18839529caSEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19839529caSEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20839529caSEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21839529caSEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22839529caSEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23839529caSEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24839529caSEd Maste * SUCH DAMAGE.
25839529caSEd Maste */
26839529caSEd Maste
27839529caSEd Maste #include <sys/param.h>
28839529caSEd Maste #include <assert.h>
29839529caSEd Maste #include <errno.h>
30839529caSEd Maste #include <stdlib.h>
31839529caSEd Maste #include <string.h>
32839529caSEd Maste #include <unistd.h>
33839529caSEd Maste
34839529caSEd Maste #include "_libpe.h"
35839529caSEd Maste
36*b6b6f9ccSEd Maste ELFTC_VCSID("$Id: libpe_section.c 3446 2016-05-03 01:31:17Z emaste $");
37839529caSEd Maste
38839529caSEd Maste PE_Scn *
libpe_alloc_scn(PE * pe)39839529caSEd Maste libpe_alloc_scn(PE *pe)
40839529caSEd Maste {
41839529caSEd Maste PE_Scn *ps;
42839529caSEd Maste
43839529caSEd Maste if ((ps = calloc(1, sizeof(PE_Scn))) == NULL) {
44839529caSEd Maste errno = ENOMEM;
45839529caSEd Maste return (NULL);
46839529caSEd Maste }
47839529caSEd Maste STAILQ_INIT(&ps->ps_b);
48839529caSEd Maste ps->ps_pe = pe;
49839529caSEd Maste
50839529caSEd Maste return (ps);
51839529caSEd Maste }
52839529caSEd Maste
53839529caSEd Maste void
libpe_release_scn(PE_Scn * ps)54839529caSEd Maste libpe_release_scn(PE_Scn *ps)
55839529caSEd Maste {
56839529caSEd Maste PE *pe;
57839529caSEd Maste PE_SecBuf *sb, *_sb;
58839529caSEd Maste
59839529caSEd Maste assert(ps != NULL);
60839529caSEd Maste
61839529caSEd Maste pe = ps->ps_pe;
62839529caSEd Maste
63839529caSEd Maste STAILQ_REMOVE(&pe->pe_scn, ps, _PE_Scn, ps_next);
64839529caSEd Maste
65839529caSEd Maste STAILQ_FOREACH_SAFE(sb, &ps->ps_b, sb_next, _sb)
66839529caSEd Maste libpe_release_buffer(sb);
67839529caSEd Maste
68839529caSEd Maste free(ps);
69839529caSEd Maste }
70839529caSEd Maste
71839529caSEd Maste static int
cmp_scn(PE_Scn * a,PE_Scn * b)72839529caSEd Maste cmp_scn(PE_Scn *a, PE_Scn *b)
73839529caSEd Maste {
74839529caSEd Maste
75839529caSEd Maste if (a->ps_sh.sh_addr < b->ps_sh.sh_addr)
76839529caSEd Maste return (-1);
77839529caSEd Maste else if (a->ps_sh.sh_addr == b->ps_sh.sh_addr)
78839529caSEd Maste return (0);
79839529caSEd Maste else
80839529caSEd Maste return (1);
81839529caSEd Maste }
82839529caSEd Maste
83839529caSEd Maste static void
sort_sections(PE * pe)84839529caSEd Maste sort_sections(PE *pe)
85839529caSEd Maste {
86839529caSEd Maste
87839529caSEd Maste if (STAILQ_EMPTY(&pe->pe_scn))
88839529caSEd Maste return;
89839529caSEd Maste
90839529caSEd Maste /* Sort the list of Scn by RVA in ascending order. */
91839529caSEd Maste STAILQ_SORT(&pe->pe_scn, _PE_Scn, ps_next, cmp_scn);
92839529caSEd Maste }
93839529caSEd Maste
94839529caSEd Maste int
libpe_parse_section_headers(PE * pe)95839529caSEd Maste libpe_parse_section_headers(PE *pe)
96839529caSEd Maste {
97839529caSEd Maste char tmp[sizeof(PE_SecHdr)], *hdr;
98839529caSEd Maste PE_Scn *ps;
99839529caSEd Maste PE_SecHdr *sh;
100839529caSEd Maste PE_CoffHdr *ch;
101839529caSEd Maste PE_DataDir *dd;
102839529caSEd Maste int found, i;
103839529caSEd Maste
104839529caSEd Maste assert(pe->pe_ch != NULL);
105839529caSEd Maste
106839529caSEd Maste for (i = 0; (uint16_t) i < pe->pe_ch->ch_nsec; i++) {
107839529caSEd Maste if (read(pe->pe_fd, tmp, sizeof(PE_SecHdr)) !=
108839529caSEd Maste (ssize_t) sizeof(PE_SecHdr)) {
109839529caSEd Maste pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;
110839529caSEd Maste return (0);
111839529caSEd Maste }
112839529caSEd Maste
113839529caSEd Maste if ((ps = libpe_alloc_scn(pe)) == NULL)
114839529caSEd Maste return (-1);
115839529caSEd Maste STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
116839529caSEd Maste ps->ps_ndx = ++pe->pe_nscn; /* Setion index is 1-based */
117839529caSEd Maste sh = &ps->ps_sh;
118839529caSEd Maste
119839529caSEd Maste /*
120839529caSEd Maste * Note that the section name won't be NUL-terminated if
121839529caSEd Maste * its length happens to be 8.
122839529caSEd Maste */
123839529caSEd Maste memcpy(sh->sh_name, tmp, sizeof(sh->sh_name));
124839529caSEd Maste hdr = tmp + 8;
125839529caSEd Maste PE_READ32(hdr, sh->sh_virtsize);
126839529caSEd Maste PE_READ32(hdr, sh->sh_addr);
127839529caSEd Maste PE_READ32(hdr, sh->sh_rawsize);
128839529caSEd Maste PE_READ32(hdr, sh->sh_rawptr);
129839529caSEd Maste PE_READ32(hdr, sh->sh_relocptr);
130839529caSEd Maste PE_READ32(hdr, sh->sh_lineptr);
131839529caSEd Maste PE_READ16(hdr, sh->sh_nreloc);
132839529caSEd Maste PE_READ16(hdr, sh->sh_nline);
133839529caSEd Maste PE_READ32(hdr, sh->sh_char);
134839529caSEd Maste }
135839529caSEd Maste
136839529caSEd Maste /*
137839529caSEd Maste * For all the data directories that don't belong to any section,
138839529caSEd Maste * we create pseudo sections for them to make layout easier.
139839529caSEd Maste */
140839529caSEd Maste dd = pe->pe_dd;
141839529caSEd Maste if (dd != NULL && dd->dd_total > 0) {
142839529caSEd Maste for (i = 0; (uint32_t) i < pe->pe_dd->dd_total; i++) {
143839529caSEd Maste if (dd->dd_e[i].de_size == 0)
144839529caSEd Maste continue;
145839529caSEd Maste found = 0;
146839529caSEd Maste STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
147839529caSEd Maste sh = &ps->ps_sh;
148839529caSEd Maste if (dd->dd_e[i].de_addr >= sh->sh_addr &&
149839529caSEd Maste dd->dd_e[i].de_addr + dd->dd_e[i].de_size <=
150839529caSEd Maste sh->sh_addr + sh->sh_virtsize) {
151839529caSEd Maste found = 1;
152839529caSEd Maste break;
153839529caSEd Maste }
154839529caSEd Maste }
155839529caSEd Maste if (found)
156839529caSEd Maste continue;
157839529caSEd Maste
158839529caSEd Maste if ((ps = libpe_alloc_scn(pe)) == NULL)
159839529caSEd Maste return (-1);
160839529caSEd Maste STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
161839529caSEd Maste ps->ps_ndx = 0xFFFF0000U | i;
162839529caSEd Maste sh = &ps->ps_sh;
163839529caSEd Maste sh->sh_rawptr = dd->dd_e[i].de_addr; /* FIXME */
164839529caSEd Maste sh->sh_rawsize = dd->dd_e[i].de_size;
165839529caSEd Maste }
166839529caSEd Maste }
167839529caSEd Maste
168839529caSEd Maste /*
169839529caSEd Maste * Also consider the COFF symbol table as a pseudo section.
170839529caSEd Maste */
171839529caSEd Maste ch = pe->pe_ch;
172839529caSEd Maste if (ch->ch_nsym > 0) {
173839529caSEd Maste if ((ps = libpe_alloc_scn(pe)) == NULL)
174839529caSEd Maste return (-1);
175839529caSEd Maste STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
176839529caSEd Maste ps->ps_ndx = 0xFFFFFFFFU;
177839529caSEd Maste sh = &ps->ps_sh;
178839529caSEd Maste sh->sh_rawptr = ch->ch_symptr;
179839529caSEd Maste sh->sh_rawsize = ch->ch_nsym * PE_SYM_ENTRY_SIZE;
180839529caSEd Maste pe->pe_nsym = ch->ch_nsym;
181839529caSEd Maste }
182839529caSEd Maste
183839529caSEd Maste /* PE file headers initialization is complete if we reach here. */
184839529caSEd Maste return (0);
185839529caSEd Maste }
186839529caSEd Maste
187839529caSEd Maste int
libpe_load_section(PE * pe,PE_Scn * ps)188839529caSEd Maste libpe_load_section(PE *pe, PE_Scn *ps)
189839529caSEd Maste {
190839529caSEd Maste PE_SecHdr *sh;
191839529caSEd Maste PE_SecBuf *sb;
192839529caSEd Maste size_t sz;
193839529caSEd Maste char tmp[4];
194839529caSEd Maste
195839529caSEd Maste assert(pe != NULL && ps != NULL);
196839529caSEd Maste assert((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0);
197839529caSEd Maste
198839529caSEd Maste sh = &ps->ps_sh;
199839529caSEd Maste
200839529caSEd Maste /* Allocate a PE_SecBuf struct without buffer for empty sections. */
201839529caSEd Maste if (sh->sh_rawsize == 0) {
202839529caSEd Maste (void) libpe_alloc_buffer(ps, 0);
203839529caSEd Maste ps->ps_flags |= LIBPE_F_LOAD_SECTION;
204839529caSEd Maste return (0);
205839529caSEd Maste }
206839529caSEd Maste
207839529caSEd Maste if ((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0) {
208839529caSEd Maste if (lseek(pe->pe_fd, (off_t) sh->sh_rawptr, SEEK_SET) < 0) {
209839529caSEd Maste errno = EIO;
210839529caSEd Maste return (-1);
211839529caSEd Maste }
212839529caSEd Maste }
213839529caSEd Maste
214839529caSEd Maste if ((sb = libpe_alloc_buffer(ps, sh->sh_rawsize)) == NULL)
215839529caSEd Maste return (-1);
216839529caSEd Maste
217839529caSEd Maste if (read(pe->pe_fd, sb->sb_pb.pb_buf, sh->sh_rawsize) !=
218839529caSEd Maste (ssize_t) sh->sh_rawsize) {
219839529caSEd Maste errno = EIO;
220839529caSEd Maste return (-1);
221839529caSEd Maste }
222839529caSEd Maste
223839529caSEd Maste if (ps->ps_ndx == 0xFFFFFFFFU) {
224839529caSEd Maste /*
225839529caSEd Maste * Index 0xFFFFFFFF indicates this section is a pseudo
226839529caSEd Maste * section that contains the COFF symbol table. We should
227839529caSEd Maste * read in the string table right after it.
228839529caSEd Maste */
229839529caSEd Maste if (read(pe->pe_fd, tmp, sizeof(tmp)) !=
230839529caSEd Maste (ssize_t) sizeof(tmp)) {
231839529caSEd Maste errno = EIO;
232839529caSEd Maste return (-1);
233839529caSEd Maste }
234839529caSEd Maste sz = le32dec(tmp);
235839529caSEd Maste
236839529caSEd Maste /*
237839529caSEd Maste * The minimum value for the size field is 4, which indicates
238839529caSEd Maste * there is no string table.
239839529caSEd Maste */
240839529caSEd Maste if (sz > 4) {
241839529caSEd Maste sz -= 4;
242839529caSEd Maste if ((sb = libpe_alloc_buffer(ps, sz)) == NULL)
243839529caSEd Maste return (-1);
244839529caSEd Maste if (read(pe->pe_fd, sb->sb_pb.pb_buf, sz) !=
245839529caSEd Maste (ssize_t) sz) {
246839529caSEd Maste errno = EIO;
247839529caSEd Maste return (-1);
248839529caSEd Maste }
249839529caSEd Maste }
250839529caSEd Maste }
251839529caSEd Maste
252839529caSEd Maste ps->ps_flags |= LIBPE_F_LOAD_SECTION;
253839529caSEd Maste
254839529caSEd Maste return (0);
255839529caSEd Maste }
256839529caSEd Maste
257839529caSEd Maste int
libpe_load_all_sections(PE * pe)258839529caSEd Maste libpe_load_all_sections(PE *pe)
259839529caSEd Maste {
260839529caSEd Maste PE_Scn *ps;
261839529caSEd Maste PE_SecHdr *sh;
262839529caSEd Maste unsigned r, s;
263839529caSEd Maste off_t off;
264839529caSEd Maste char tmp[256];
265839529caSEd Maste
266839529caSEd Maste /* Calculate the current offset into the file. */
267839529caSEd Maste off = 0;
268839529caSEd Maste if (pe->pe_dh != NULL)
269839529caSEd Maste off += pe->pe_dh->dh_lfanew + 4;
270839529caSEd Maste if (pe->pe_ch != NULL)
271839529caSEd Maste off += sizeof(PE_CoffHdr) + pe->pe_ch->ch_optsize;
272839529caSEd Maste
273839529caSEd Maste STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
274839529caSEd Maste if (ps->ps_flags & LIBPE_F_LOAD_SECTION)
275839529caSEd Maste continue;
276839529caSEd Maste sh = &ps->ps_sh;
277839529caSEd Maste
278839529caSEd Maste /*
279839529caSEd Maste * For special files, we consume the padding in between
280839529caSEd Maste * and advance to the section offset.
281839529caSEd Maste */
282839529caSEd Maste if (pe->pe_flags & LIBPE_F_SPECIAL_FILE) {
283839529caSEd Maste /* Can't go backwards. */
284839529caSEd Maste if (off > sh->sh_rawptr) {
285839529caSEd Maste errno = EIO;
286839529caSEd Maste return (-1);
287839529caSEd Maste }
288839529caSEd Maste if (off < sh->sh_rawptr) {
289839529caSEd Maste r = sh->sh_rawptr - off;
290839529caSEd Maste for (; r > 0; r -= s) {
291839529caSEd Maste s = r > sizeof(tmp) ? sizeof(tmp) : r;
292839529caSEd Maste if (read(pe->pe_fd, tmp, s) !=
293839529caSEd Maste (ssize_t) s) {
294839529caSEd Maste errno = EIO;
295839529caSEd Maste return (-1);
296839529caSEd Maste }
297839529caSEd Maste }
298839529caSEd Maste }
299839529caSEd Maste }
300839529caSEd Maste
301839529caSEd Maste /* Load the section content. */
302839529caSEd Maste if (libpe_load_section(pe, ps) < 0)
303839529caSEd Maste return (-1);
304839529caSEd Maste }
305839529caSEd Maste
306839529caSEd Maste return (0);
307839529caSEd Maste }
308839529caSEd Maste
309839529caSEd Maste int
libpe_resync_sections(PE * pe,off_t off)310839529caSEd Maste libpe_resync_sections(PE *pe, off_t off)
311839529caSEd Maste {
312839529caSEd Maste PE_Scn *ps;
313839529caSEd Maste PE_SecHdr *sh;
314839529caSEd Maste size_t falign, nsec;
315839529caSEd Maste
316839529caSEd Maste /* Firstly, sort all sections by their file offsets. */
317839529caSEd Maste sort_sections(pe);
318839529caSEd Maste
319839529caSEd Maste /* Count the number of sections. */
320839529caSEd Maste nsec = 0;
321839529caSEd Maste STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
322839529caSEd Maste if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
323839529caSEd Maste continue;
324839529caSEd Maste if (ps->ps_ndx & 0xFFFF0000U)
325839529caSEd Maste continue;
326839529caSEd Maste nsec++;
327839529caSEd Maste }
328839529caSEd Maste pe->pe_nscn = nsec;
329839529caSEd Maste
330839529caSEd Maste /*
331839529caSEd Maste * Calculate the file offset for the first section. (`off' is
332839529caSEd Maste * currently pointing to the COFF header.)
333839529caSEd Maste */
334839529caSEd Maste off += sizeof(PE_CoffHdr);
335839529caSEd Maste if (pe->pe_ch != NULL && pe->pe_ch->ch_optsize > 0)
336839529caSEd Maste off += pe->pe_ch->ch_optsize;
337839529caSEd Maste else {
338839529caSEd Maste switch (pe->pe_obj) {
339839529caSEd Maste case PE_O_PE32:
340839529caSEd Maste off += PE_COFF_OPT_SIZE_32;
341839529caSEd Maste break;
342839529caSEd Maste case PE_O_PE32P:
343839529caSEd Maste off += PE_COFF_OPT_SIZE_32P;
344839529caSEd Maste break;
345839529caSEd Maste case PE_O_COFF:
346839529caSEd Maste default:
347839529caSEd Maste break;
348839529caSEd Maste }
349839529caSEd Maste }
350839529caSEd Maste off += nsec * sizeof(PE_SecHdr);
351839529caSEd Maste
352839529caSEd Maste /*
353839529caSEd Maste * Determine the file alignment for sections.
354839529caSEd Maste */
355839529caSEd Maste if (pe->pe_oh != NULL && pe->pe_oh->oh_filealign > 0)
356839529caSEd Maste falign = pe->pe_oh->oh_filealign;
357839529caSEd Maste else {
358839529caSEd Maste /*
359839529caSEd Maste * Use the default file alignment defined by the
360839529caSEd Maste * PE/COFF specification.
361839529caSEd Maste */
362839529caSEd Maste if (pe->pe_obj == PE_O_COFF)
363839529caSEd Maste falign = 4;
364839529caSEd Maste else
365839529caSEd Maste falign = 512;
366839529caSEd Maste }
367839529caSEd Maste
368839529caSEd Maste /*
369839529caSEd Maste * Step through each section (and pseduo section) and verify
370839529caSEd Maste * alignment constraint and overlapping, make adjustment if need.
371839529caSEd Maste */
372839529caSEd Maste pe->pe_rvamax = 0;
373839529caSEd Maste STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
374839529caSEd Maste if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
375839529caSEd Maste continue;
376839529caSEd Maste
377839529caSEd Maste sh = &ps->ps_sh;
378839529caSEd Maste
379839529caSEd Maste if (sh->sh_addr + sh->sh_virtsize > pe->pe_rvamax)
380839529caSEd Maste pe->pe_rvamax = sh->sh_addr + sh->sh_virtsize;
381839529caSEd Maste
382839529caSEd Maste if (ps->ps_ndx & 0xFFFF0000U)
383839529caSEd Maste ps->ps_falign = 4;
384839529caSEd Maste else
385839529caSEd Maste ps->ps_falign = falign;
386839529caSEd Maste
387839529caSEd Maste off = roundup(off, ps->ps_falign);
388839529caSEd Maste
389839529caSEd Maste if (off != sh->sh_rawptr)
390839529caSEd Maste ps->ps_flags |= PE_F_DIRTY;
391839529caSEd Maste
392839529caSEd Maste if (ps->ps_flags & PE_F_DIRTY) {
393839529caSEd Maste if ((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0) {
394839529caSEd Maste if (libpe_load_section(pe, ps) < 0)
395839529caSEd Maste return (-1);
396839529caSEd Maste }
397839529caSEd Maste sh->sh_rawsize = libpe_resync_buffers(ps);
398839529caSEd Maste }
399839529caSEd Maste
400839529caSEd Maste /*
401839529caSEd Maste * Sections only contains uninitialized data should set
402839529caSEd Maste * PointerToRawData to zero according to the PE/COFF
403839529caSEd Maste * specification.
404839529caSEd Maste */
405839529caSEd Maste if (sh->sh_rawsize == 0)
406839529caSEd Maste sh->sh_rawptr = 0;
407839529caSEd Maste else
408839529caSEd Maste sh->sh_rawptr = off;
409839529caSEd Maste
410839529caSEd Maste off += sh->sh_rawsize;
411839529caSEd Maste }
412839529caSEd Maste
413839529caSEd Maste return (0);
414839529caSEd Maste }
415839529caSEd Maste
416839529caSEd Maste off_t
libpe_write_section_headers(PE * pe,off_t off)417839529caSEd Maste libpe_write_section_headers(PE *pe, off_t off)
418839529caSEd Maste {
419839529caSEd Maste char tmp[sizeof(PE_SecHdr)], *hdr;
420839529caSEd Maste PE_Scn *ps;
421839529caSEd Maste PE_SecHdr *sh;
422839529caSEd Maste
423839529caSEd Maste if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER || pe->pe_nscn == 0)
424839529caSEd Maste return (off);
425839529caSEd Maste
426839529caSEd Maste if ((pe->pe_flags & LIBPE_F_DIRTY_SEC_HEADER) == 0) {
427839529caSEd Maste off += sizeof(PE_SecHdr) * pe->pe_ch->ch_nsec;
428839529caSEd Maste return (off);
429839529caSEd Maste }
430839529caSEd Maste
431839529caSEd Maste STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
432839529caSEd Maste if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
433839529caSEd Maste continue;
434839529caSEd Maste if (ps->ps_ndx & 0xFFFF0000U)
435839529caSEd Maste continue;
436839529caSEd Maste if ((pe->pe_flags & LIBPE_F_DIRTY_SEC_HEADER) == 0 &&
437839529caSEd Maste (ps->ps_flags & PE_F_DIRTY) == 0)
438839529caSEd Maste goto next_header;
439839529caSEd Maste
440839529caSEd Maste sh = &ps->ps_sh;
441839529caSEd Maste
442839529caSEd Maste memcpy(tmp, sh->sh_name, sizeof(sh->sh_name));
443839529caSEd Maste hdr = tmp + 8;
444839529caSEd Maste PE_WRITE32(hdr, sh->sh_virtsize);
445839529caSEd Maste PE_WRITE32(hdr, sh->sh_addr);
446839529caSEd Maste PE_WRITE32(hdr, sh->sh_rawsize);
447839529caSEd Maste PE_WRITE32(hdr, sh->sh_rawptr);
448839529caSEd Maste PE_WRITE32(hdr, sh->sh_relocptr);
449839529caSEd Maste PE_WRITE32(hdr, sh->sh_lineptr);
450839529caSEd Maste PE_WRITE16(hdr, sh->sh_nreloc);
451839529caSEd Maste PE_WRITE16(hdr, sh->sh_nline);
452839529caSEd Maste PE_WRITE32(hdr, sh->sh_char);
453839529caSEd Maste
454839529caSEd Maste if (write(pe->pe_fd, tmp, sizeof(PE_SecHdr)) !=
455839529caSEd Maste (ssize_t) sizeof(PE_SecHdr)) {
456839529caSEd Maste errno = EIO;
457839529caSEd Maste return (-1);
458839529caSEd Maste }
459839529caSEd Maste
460839529caSEd Maste next_header:
461839529caSEd Maste off += sizeof(PE_SecHdr);
462839529caSEd Maste }
463839529caSEd Maste
464839529caSEd Maste return (off);
465839529caSEd Maste }
466839529caSEd Maste
467839529caSEd Maste off_t
libpe_write_sections(PE * pe,off_t off)468839529caSEd Maste libpe_write_sections(PE *pe, off_t off)
469839529caSEd Maste {
470839529caSEd Maste PE_Scn *ps;
471839529caSEd Maste PE_SecHdr *sh;
472839529caSEd Maste
473839529caSEd Maste if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER)
474839529caSEd Maste return (off);
475839529caSEd Maste
476839529caSEd Maste STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
477839529caSEd Maste sh = &ps->ps_sh;
478839529caSEd Maste
479839529caSEd Maste if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
480839529caSEd Maste continue;
481839529caSEd Maste
482839529caSEd Maste /* Skip empty sections. */
483839529caSEd Maste if (sh->sh_rawptr == 0 || sh->sh_rawsize == 0)
484839529caSEd Maste continue;
485839529caSEd Maste
486839529caSEd Maste /*
487839529caSEd Maste * Padding between sections. (padding always written
488839529caSEd Maste * in case the the section headers or sections are
489*b6b6f9ccSEd Maste * moved or shrunk.)
490839529caSEd Maste */
491839529caSEd Maste assert(off <= sh->sh_rawptr);
492839529caSEd Maste if (off < sh->sh_rawptr)
493839529caSEd Maste libpe_pad(pe, sh->sh_rawptr - off);
494839529caSEd Maste
495839529caSEd Maste if ((ps->ps_flags & PE_F_DIRTY) == 0) {
496839529caSEd Maste assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
497839529caSEd Maste if (lseek(pe->pe_fd,
498839529caSEd Maste (off_t) (sh->sh_rawptr + sh->sh_rawsize),
499839529caSEd Maste SEEK_SET) < 0) {
500839529caSEd Maste errno = EIO;
501839529caSEd Maste return (-1);
502839529caSEd Maste }
503839529caSEd Maste off = sh->sh_rawptr + sh->sh_rawsize;
504839529caSEd Maste continue;
505839529caSEd Maste }
506839529caSEd Maste
507839529caSEd Maste off = sh->sh_rawptr;
508839529caSEd Maste
509839529caSEd Maste if (libpe_write_buffers(ps) < 0)
510839529caSEd Maste return (-1);
511839529caSEd Maste
512839529caSEd Maste off += sh->sh_rawsize;
513839529caSEd Maste
514839529caSEd Maste ps->ps_flags &= ~PE_F_DIRTY;
515839529caSEd Maste }
516839529caSEd Maste
517839529caSEd Maste return (off);
518839529caSEd Maste }
519