xref: /freebsd/contrib/elftoolchain/libpe/libpe_section.c (revision b6b6f9cc7c36b4ff856e2cee50cb825d82a329fe)
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