1295484Semaste/*-
2295484Semaste * Copyright (c) 2015 Kai Wang
3295484Semaste * All rights reserved.
4295484Semaste *
5295484Semaste * Redistribution and use in source and binary forms, with or without
6295484Semaste * modification, are permitted provided that the following conditions
7295484Semaste * are met:
8295484Semaste * 1. Redistributions of source code must retain the above copyright
9295484Semaste *    notice, this list of conditions and the following disclaimer.
10295484Semaste * 2. Redistributions in binary form must reproduce the above copyright
11295484Semaste *    notice, this list of conditions and the following disclaimer in the
12295484Semaste *    documentation and/or other materials provided with the distribution.
13295484Semaste *
14295484Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15295484Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16295484Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17295484Semaste * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18295484Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19295484Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20295484Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21295484Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22295484Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23295484Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24295484Semaste * SUCH DAMAGE.
25295484Semaste */
26295484Semaste
27295484Semaste#include <sys/param.h>
28295484Semaste#include <assert.h>
29295484Semaste#include <errno.h>
30295484Semaste#include <stdlib.h>
31295484Semaste#include <string.h>
32295484Semaste#include <time.h>
33295484Semaste#include <unistd.h>
34295484Semaste
35295484Semaste#include "_libpe.h"
36295484Semaste
37295484SemasteELFTC_VCSID("$Id: libpe_coff.c 3326 2016-01-16 17:46:17Z kaiwang27 $");
38295484Semaste
39295484Semasteint
40295484Semastelibpe_parse_coff_header(PE *pe, char *hdr)
41295484Semaste{
42295484Semaste	char tmp[128];
43295484Semaste	PE_CoffHdr *ch;
44295484Semaste	PE_OptHdr *oh;
45295484Semaste	PE_DataDir *dd;
46295484Semaste	unsigned p, r, s;
47295484Semaste	int i;
48295484Semaste
49295484Semaste	if ((ch = malloc(sizeof(PE_CoffHdr))) == NULL) {
50295484Semaste		errno = ENOMEM;
51295484Semaste		return (-1);
52295484Semaste	}
53295484Semaste
54295484Semaste	PE_READ16(hdr, ch->ch_machine);
55295484Semaste	PE_READ16(hdr, ch->ch_nsec);
56295484Semaste	PE_READ32(hdr, ch->ch_timestamp);
57295484Semaste	PE_READ32(hdr, ch->ch_symptr);
58295484Semaste	PE_READ32(hdr, ch->ch_nsym);
59295484Semaste	PE_READ16(hdr, ch->ch_optsize);
60295484Semaste	PE_READ16(hdr, ch->ch_char);
61295484Semaste
62295484Semaste	pe->pe_ch = ch;
63295484Semaste
64295484Semaste	/*
65295484Semaste	 * The Optional header is omitted for object files.
66295484Semaste	 */
67295484Semaste	if (ch->ch_optsize == 0)
68295484Semaste		return (libpe_parse_section_headers(pe));
69295484Semaste
70295484Semaste	if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
71295484Semaste		errno = ENOMEM;
72295484Semaste		return (-1);
73295484Semaste	}
74295484Semaste	pe->pe_oh = oh;
75295484Semaste
76295484Semaste#define READ_OPT(n)							\
77295484Semaste	do {								\
78295484Semaste		/*							\
79295484Semaste		 * Since the Optional Header size is variable, we must	\
80295484Semaste		 * check if the requested read size will overrun the	\
81295484Semaste		 * remaining header bytes.				\
82295484Semaste		 */							\
83295484Semaste		if (p + (n) > ch->ch_optsize) {				\
84295484Semaste			/* Consume the "extra" bytes */			\
85295484Semaste			r = ch->ch_optsize - p;				\
86295484Semaste			if (read(pe->pe_fd, tmp, r) != (ssize_t) r) {	\
87295484Semaste				pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;\
88295484Semaste				return (0);				\
89295484Semaste			}						\
90295484Semaste			return (libpe_parse_section_headers(pe));	\
91295484Semaste		}							\
92295484Semaste		if (read(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) {	\
93295484Semaste			pe->pe_flags |= LIBPE_F_BAD_OPT_HEADER;	\
94295484Semaste			return (0);					\
95295484Semaste		}							\
96295484Semaste		p += (n);						\
97295484Semaste	} while (0)
98295484Semaste#define	READ_OPT8(v) do { READ_OPT(1); (v) = *tmp; } while(0)
99295484Semaste#define	READ_OPT16(v) do { READ_OPT(2); (v) = le16dec(tmp); } while(0)
100295484Semaste#define	READ_OPT32(v) do { READ_OPT(4); (v) = le32dec(tmp); } while(0)
101295484Semaste#define	READ_OPT64(v) do { READ_OPT(8); (v) = le64dec(tmp); } while(0)
102295484Semaste
103295484Semaste	/*
104295484Semaste	 * Read in the Optional header. Size of some fields are depending
105295484Semaste	 * on the PE format specified by the oh_magic field. (PE32 or PE32+)
106295484Semaste	 */
107295484Semaste
108295484Semaste	p = 0;
109295484Semaste	READ_OPT16(oh->oh_magic);
110295484Semaste	if (oh->oh_magic == PE_FORMAT_32P)
111295484Semaste		pe->pe_obj = PE_O_PE32P;
112295484Semaste	READ_OPT8(oh->oh_ldvermajor);
113295484Semaste	READ_OPT8(oh->oh_ldverminor);
114295484Semaste	READ_OPT32(oh->oh_textsize);
115295484Semaste	READ_OPT32(oh->oh_datasize);
116295484Semaste	READ_OPT32(oh->oh_bsssize);
117295484Semaste	READ_OPT32(oh->oh_entry);
118295484Semaste	READ_OPT32(oh->oh_textbase);
119295484Semaste	if (oh->oh_magic != PE_FORMAT_32P) {
120295484Semaste		READ_OPT32(oh->oh_database);
121295484Semaste		READ_OPT32(oh->oh_imgbase);
122295484Semaste	} else
123295484Semaste		READ_OPT64(oh->oh_imgbase);
124295484Semaste	READ_OPT32(oh->oh_secalign);
125295484Semaste	READ_OPT32(oh->oh_filealign);
126295484Semaste	READ_OPT16(oh->oh_osvermajor);
127295484Semaste	READ_OPT16(oh->oh_osverminor);
128295484Semaste	READ_OPT16(oh->oh_imgvermajor);
129295484Semaste	READ_OPT16(oh->oh_imgverminor);
130295484Semaste	READ_OPT16(oh->oh_subvermajor);
131295484Semaste	READ_OPT16(oh->oh_subverminor);
132295484Semaste	READ_OPT32(oh->oh_win32ver);
133295484Semaste	READ_OPT32(oh->oh_imgsize);
134295484Semaste	READ_OPT32(oh->oh_hdrsize);
135295484Semaste	READ_OPT32(oh->oh_checksum);
136295484Semaste	READ_OPT16(oh->oh_subsystem);
137295484Semaste	READ_OPT16(oh->oh_dllchar);
138295484Semaste	if (oh->oh_magic != PE_FORMAT_32P) {
139295484Semaste		READ_OPT32(oh->oh_stacksizer);
140295484Semaste		READ_OPT32(oh->oh_stacksizec);
141295484Semaste		READ_OPT32(oh->oh_heapsizer);
142295484Semaste		READ_OPT32(oh->oh_heapsizec);
143295484Semaste	} else {
144295484Semaste		READ_OPT64(oh->oh_stacksizer);
145295484Semaste		READ_OPT64(oh->oh_stacksizec);
146295484Semaste		READ_OPT64(oh->oh_heapsizer);
147295484Semaste		READ_OPT64(oh->oh_heapsizec);
148295484Semaste	}
149295484Semaste	READ_OPT32(oh->oh_ldrflags);
150295484Semaste	READ_OPT32(oh->oh_ndatadir);
151295484Semaste
152295484Semaste	/*
153295484Semaste	 * Read in the Data Directories.
154295484Semaste	 */
155295484Semaste
156295484Semaste	if (oh->oh_ndatadir > 0) {
157295484Semaste		if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
158295484Semaste			errno = ENOMEM;
159295484Semaste			return (-1);
160295484Semaste		}
161295484Semaste		pe->pe_dd = dd;
162295484Semaste
163295484Semaste		dd->dd_total = oh->oh_ndatadir < PE_DD_MAX ? oh->oh_ndatadir :
164295484Semaste			PE_DD_MAX;
165295484Semaste
166295484Semaste		for (i = 0; (uint32_t) i < dd->dd_total; i++) {
167295484Semaste			READ_OPT32(dd->dd_e[i].de_addr);
168295484Semaste			READ_OPT32(dd->dd_e[i].de_size);
169295484Semaste		}
170295484Semaste	}
171295484Semaste
172295484Semaste	/* Consume the remaining bytes in the Optional header, if any. */
173295484Semaste	if (ch->ch_optsize > p) {
174295484Semaste		r = ch->ch_optsize - p;
175295484Semaste		for (; r > 0; r -= s) {
176295484Semaste			s = r > sizeof(tmp) ? sizeof(tmp) : r;
177295484Semaste			if (read(pe->pe_fd, tmp, s) != (ssize_t) s) {
178295484Semaste				pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;
179295484Semaste				return (0);
180295484Semaste			}
181295484Semaste		}
182295484Semaste	}
183295484Semaste
184295484Semaste	return (libpe_parse_section_headers(pe));
185295484Semaste}
186295484Semaste
187295484Semasteoff_t
188295484Semastelibpe_write_pe_header(PE *pe, off_t off)
189295484Semaste{
190295484Semaste	char tmp[4];
191295484Semaste
192295484Semaste	if (pe->pe_cmd == PE_C_RDWR &&
193295484Semaste	    (pe->pe_flags & LIBPE_F_BAD_PE_HEADER) == 0) {
194295484Semaste		assert(pe->pe_dh != NULL);
195295484Semaste		off = lseek(pe->pe_fd, (off_t) pe->pe_dh->dh_lfanew + 4,
196295484Semaste		    SEEK_SET);
197295484Semaste		return (off);
198295484Semaste	}
199295484Semaste
200295484Semaste	/*
201295484Semaste	 * PE Header should to be aligned on 8-byte boundary according to
202295484Semaste	 * the PE/COFF specification.
203295484Semaste	 */
204295484Semaste	if ((off = libpe_align(pe, off, 8)) < 0)
205295484Semaste		return (-1);
206295484Semaste
207295484Semaste	le32enc(tmp, PE_SIGNATURE);
208295484Semaste	if (write(pe->pe_fd, tmp, sizeof(tmp)) != (ssize_t) sizeof(tmp)) {
209295484Semaste		errno = EIO;
210295484Semaste		return (-1);
211295484Semaste	}
212295484Semaste
213295484Semaste	off += 4;
214295484Semaste
215295484Semaste	pe->pe_flags &= ~LIBPE_F_BAD_PE_HEADER;
216295484Semaste
217295484Semaste	/* Trigger rewrite for the following headers. */
218295484Semaste	pe->pe_flags |= LIBPE_F_DIRTY_COFF_HEADER;
219295484Semaste	pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
220295484Semaste
221295484Semaste	return (off);
222295484Semaste}
223295484Semaste
224295484Semasteoff_t
225295484Semastelibpe_write_coff_header(PE *pe, off_t off)
226295484Semaste{
227295484Semaste	char tmp[128], *hdr;
228295484Semaste	PE_CoffHdr *ch;
229295484Semaste	PE_DataDir *dd;
230295484Semaste	PE_OptHdr *oh;
231295484Semaste	PE_Scn *ps;
232295484Semaste	PE_SecHdr *sh;
233295484Semaste	unsigned p;
234295484Semaste	uint32_t reloc_rva, reloc_sz;
235295484Semaste	int i, reloc;
236295484Semaste
237295484Semaste	reloc = 0;
238295484Semaste	reloc_rva = reloc_sz = 0;
239295484Semaste
240295484Semaste	if (pe->pe_cmd == PE_C_RDWR) {
241295484Semaste		assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
242295484Semaste
243295484Semaste		if ((pe->pe_flags & LIBPE_F_DIRTY_COFF_HEADER) == 0 &&
244295484Semaste		    (pe->pe_flags & LIBPE_F_BAD_COFF_HEADER) == 0) {
245295484Semaste			if (lseek(pe->pe_fd, (off_t) sizeof(PE_CoffHdr),
246295484Semaste			    SEEK_CUR) < 0) {
247295484Semaste				errno = EIO;
248295484Semaste				return (-1);
249295484Semaste			}
250295484Semaste			off += sizeof(PE_CoffHdr);
251295484Semaste			assert(pe->pe_ch != NULL);
252295484Semaste			ch = pe->pe_ch;
253295484Semaste			goto coff_done;
254295484Semaste		}
255295484Semaste
256295484Semaste		/* lseek(2) to the offset of the COFF header. */
257295484Semaste		if (lseek(pe->pe_fd, off, SEEK_SET) < 0) {
258295484Semaste			errno = EIO;
259295484Semaste			return (-1);
260295484Semaste		}
261295484Semaste	}
262295484Semaste
263295484Semaste	if (pe->pe_ch == NULL) {
264295484Semaste		if ((ch = calloc(1, sizeof(PE_CoffHdr))) == NULL) {
265295484Semaste			errno = ENOMEM;
266295484Semaste			return (-1);
267295484Semaste		}
268295484Semaste		pe->pe_ch = ch;
269295484Semaste
270295484Semaste		/*
271295484Semaste		 * Default value for ch_machine if not provided by the
272295484Semaste		 * application.
273295484Semaste		 */
274295484Semaste		if (pe->pe_obj == PE_O_PE32P)
275295484Semaste			ch->ch_machine = IMAGE_FILE_MACHINE_AMD64;
276295484Semaste		else
277295484Semaste			ch->ch_machine = IMAGE_FILE_MACHINE_I386;
278295484Semaste
279295484Semaste	} else
280295484Semaste		ch = pe->pe_ch;
281295484Semaste
282295484Semaste	if (!ch->ch_timestamp)
283295484Semaste		ch->ch_timestamp = time(NULL);
284295484Semaste
285295484Semaste	if (pe->pe_obj == PE_O_PE32) {
286295484Semaste		if (!ch->ch_optsize)
287295484Semaste			ch->ch_optsize = PE_COFF_OPT_SIZE_32;
288295484Semaste		ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
289295484Semaste		    IMAGE_FILE_32BIT_MACHINE;
290295484Semaste	} else if (pe->pe_obj == PE_O_PE32P) {
291295484Semaste		if (!ch->ch_optsize)
292295484Semaste			ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
293295484Semaste		ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
294295484Semaste		    IMAGE_FILE_LARGE_ADDRESS_AWARE;
295295484Semaste	} else
296295484Semaste		ch->ch_optsize = 0;
297295484Semaste
298295484Semaste	/*
299295484Semaste	 * COFF line number is deprecated by the PE/COFF
300295484Semaste	 * specification. COFF symbol table is deprecated
301295484Semaste	 * for executables.
302295484Semaste	 */
303295484Semaste	ch->ch_char |= IMAGE_FILE_LINE_NUMS_STRIPPED;
304295484Semaste	if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P)
305295484Semaste		ch->ch_char |= IMAGE_FILE_LOCAL_SYMS_STRIPPED;
306295484Semaste
307295484Semaste	ch->ch_nsec = pe->pe_nscn;
308295484Semaste
309295484Semaste	STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
310295484Semaste		sh = &ps->ps_sh;
311295484Semaste
312295484Semaste		if (ps->ps_ndx == 0xFFFFFFFFU) {
313295484Semaste			ch->ch_symptr = sh->sh_rawptr;
314295484Semaste			ch->ch_nsym = pe->pe_nsym;
315295484Semaste		}
316295484Semaste
317295484Semaste		if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P) {
318295484Semaste			if (ps->ps_ndx == (0xFFFF0000 | PE_DD_BASERELOC) ||
319295484Semaste			    strncmp(sh->sh_name, ".reloc", strlen(".reloc")) ==
320295484Semaste			    0) {
321295484Semaste				reloc = 1;
322295484Semaste				reloc_rva = sh->sh_addr;
323295484Semaste				reloc_sz = sh->sh_virtsize;
324295484Semaste			}
325295484Semaste		}
326295484Semaste	}
327295484Semaste
328295484Semaste	if (!reloc)
329295484Semaste		ch->ch_char |= IMAGE_FILE_RELOCS_STRIPPED;
330295484Semaste
331295484Semaste	if (pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) {
332295484Semaste		if (pe->pe_obj == PE_O_PE32)
333295484Semaste			ch->ch_optsize = PE_COFF_OPT_SIZE_32;
334295484Semaste		else if (pe->pe_obj == PE_O_PE32P)
335295484Semaste			ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
336295484Semaste		else
337295484Semaste			ch->ch_optsize = 0;
338295484Semaste	}
339295484Semaste
340295484Semaste	/*
341295484Semaste	 * Write the COFF header.
342295484Semaste	 */
343295484Semaste	hdr = tmp;
344295484Semaste	PE_WRITE16(hdr, ch->ch_machine);
345295484Semaste	PE_WRITE16(hdr, ch->ch_nsec);
346295484Semaste	PE_WRITE32(hdr, ch->ch_timestamp);
347295484Semaste	PE_WRITE32(hdr, ch->ch_symptr);
348295484Semaste	PE_WRITE32(hdr, ch->ch_nsym);
349295484Semaste	PE_WRITE16(hdr, ch->ch_optsize);
350295484Semaste	PE_WRITE16(hdr, ch->ch_char);
351295484Semaste	if (write(pe->pe_fd, tmp, sizeof(PE_CoffHdr)) !=
352295484Semaste	    (ssize_t) sizeof(PE_CoffHdr)) {
353295484Semaste		errno = EIO;
354295484Semaste		return (-1);
355295484Semaste	}
356295484Semaste
357295484Semastecoff_done:
358295484Semaste	off += sizeof(PE_CoffHdr);
359295484Semaste	pe->pe_flags &= ~LIBPE_F_DIRTY_COFF_HEADER;
360295484Semaste	pe->pe_flags &= ~LIBPE_F_BAD_COFF_HEADER;
361295484Semaste	pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
362295484Semaste
363295484Semaste	if (ch->ch_optsize == 0)
364295484Semaste		return (off);
365295484Semaste
366295484Semaste	/*
367295484Semaste	 * Write the Optional header.
368295484Semaste	 */
369295484Semaste
370295484Semaste	if (pe->pe_cmd == PE_C_RDWR) {
371295484Semaste		if ((pe->pe_flags & LIBPE_F_DIRTY_OPT_HEADER) == 0 &&
372295484Semaste		    (pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) == 0) {
373295484Semaste			if (lseek(pe->pe_fd, (off_t) ch->ch_optsize,
374295484Semaste			    SEEK_CUR) < 0) {
375295484Semaste				errno = EIO;
376295484Semaste				return (-1);
377295484Semaste			}
378295484Semaste			off += ch->ch_optsize;
379295484Semaste			return (off);
380295484Semaste		}
381295484Semaste
382295484Semaste	}
383295484Semaste
384295484Semaste	if (pe->pe_oh == NULL) {
385295484Semaste		if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
386295484Semaste			errno = ENOMEM;
387295484Semaste			return (-1);
388295484Semaste		}
389295484Semaste		pe->pe_oh = oh;
390295484Semaste	} else
391295484Semaste		oh = pe->pe_oh;
392295484Semaste
393295484Semaste	if (pe->pe_obj == PE_O_PE32)
394295484Semaste		oh->oh_magic = PE_FORMAT_32;
395295484Semaste	else
396295484Semaste		oh->oh_magic = PE_FORMAT_32P;
397295484Semaste
398295484Semaste	/*
399295484Semaste	 * LinkerVersion should not be less than 2.5, which will cause
400295484Semaste	 * Windows to complain the executable is invalid in some case.
401295484Semaste	 * By default we set LinkerVersion to 2.22 (binutils 2.22)
402295484Semaste	 */
403295484Semaste	if (!oh->oh_ldvermajor && !oh->oh_ldverminor) {
404295484Semaste		oh->oh_ldvermajor = 2;
405295484Semaste		oh->oh_ldverminor = 22;
406295484Semaste	}
407295484Semaste
408295484Semaste	/*
409295484Semaste	 * The library always tries to write out all 16 data directories
410295484Semaste	 * but the actual data dir written will depend on ch_optsize.
411295484Semaste	 */
412295484Semaste	oh->oh_ndatadir = PE_DD_MAX;
413295484Semaste
414295484Semaste	if (!oh->oh_filealign)
415295484Semaste		oh->oh_filealign = 0x200;
416295484Semaste	if (!oh->oh_secalign)
417295484Semaste		oh->oh_secalign = 0x1000;
418295484Semaste	oh->oh_hdrsize = roundup(off + ch->ch_optsize + pe->pe_nscn *
419295484Semaste	    sizeof(PE_SecHdr), oh->oh_filealign);
420295484Semaste	oh->oh_imgsize = roundup(pe->pe_rvamax, oh->oh_secalign);
421295484Semaste
422295484Semaste#define WRITE_OPT(n)							\
423295484Semaste	do {								\
424295484Semaste		/*							\
425295484Semaste		 * Since the Optional Header size is variable, we must	\
426295484Semaste		 * check if the requested write size will overrun the	\
427295484Semaste		 * remaining header bytes.				\
428295484Semaste		 */							\
429295484Semaste		if (p + (n) > ch->ch_optsize) {				\
430295484Semaste			/* Pad the "extra" bytes */			\
431295484Semaste			if (libpe_pad(pe, ch->ch_optsize - p) < 0) {	\
432295484Semaste				errno = EIO;				\
433295484Semaste				return (-1);				\
434295484Semaste			}						\
435295484Semaste			goto opt_done;					\
436295484Semaste		}							\
437295484Semaste		if (write(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) {	\
438295484Semaste			errno = EIO;					\
439295484Semaste			return (-1);					\
440295484Semaste		}							\
441295484Semaste		p += (n);						\
442295484Semaste	} while (0)
443295484Semaste#define	WRITE_OPT8(v) do { *tmp = (v); WRITE_OPT(1); } while(0)
444295484Semaste#define	WRITE_OPT16(v) do { le16enc(tmp, (v)); WRITE_OPT(2); } while(0)
445295484Semaste#define	WRITE_OPT32(v) do { le32enc(tmp, (v)); WRITE_OPT(4); } while(0)
446295484Semaste#define	WRITE_OPT64(v) do { le64enc(tmp, (v)); WRITE_OPT(8); } while(0)
447295484Semaste
448295484Semaste	p = 0;
449295484Semaste	WRITE_OPT16(oh->oh_magic);
450295484Semaste	if (oh->oh_magic == PE_FORMAT_32P)
451295484Semaste		pe->pe_obj = PE_O_PE32P;
452295484Semaste	WRITE_OPT8(oh->oh_ldvermajor);
453295484Semaste	WRITE_OPT8(oh->oh_ldverminor);
454295484Semaste	WRITE_OPT32(oh->oh_textsize);
455295484Semaste	WRITE_OPT32(oh->oh_datasize);
456295484Semaste	WRITE_OPT32(oh->oh_bsssize);
457295484Semaste	WRITE_OPT32(oh->oh_entry);
458295484Semaste	WRITE_OPT32(oh->oh_textbase);
459295484Semaste	if (oh->oh_magic != PE_FORMAT_32P) {
460295484Semaste		WRITE_OPT32(oh->oh_database);
461295484Semaste		WRITE_OPT32(oh->oh_imgbase);
462295484Semaste	} else
463295484Semaste		WRITE_OPT64(oh->oh_imgbase);
464295484Semaste	WRITE_OPT32(oh->oh_secalign);
465295484Semaste	WRITE_OPT32(oh->oh_filealign);
466295484Semaste	WRITE_OPT16(oh->oh_osvermajor);
467295484Semaste	WRITE_OPT16(oh->oh_osverminor);
468295484Semaste	WRITE_OPT16(oh->oh_imgvermajor);
469295484Semaste	WRITE_OPT16(oh->oh_imgverminor);
470295484Semaste	WRITE_OPT16(oh->oh_subvermajor);
471295484Semaste	WRITE_OPT16(oh->oh_subverminor);
472295484Semaste	WRITE_OPT32(oh->oh_win32ver);
473295484Semaste	WRITE_OPT32(oh->oh_imgsize);
474295484Semaste	WRITE_OPT32(oh->oh_hdrsize);
475295484Semaste	WRITE_OPT32(oh->oh_checksum);
476295484Semaste	WRITE_OPT16(oh->oh_subsystem);
477295484Semaste	WRITE_OPT16(oh->oh_dllchar);
478295484Semaste	if (oh->oh_magic != PE_FORMAT_32P) {
479295484Semaste		WRITE_OPT32(oh->oh_stacksizer);
480295484Semaste		WRITE_OPT32(oh->oh_stacksizec);
481295484Semaste		WRITE_OPT32(oh->oh_heapsizer);
482295484Semaste		WRITE_OPT32(oh->oh_heapsizec);
483295484Semaste	} else {
484295484Semaste		WRITE_OPT64(oh->oh_stacksizer);
485295484Semaste		WRITE_OPT64(oh->oh_stacksizec);
486295484Semaste		WRITE_OPT64(oh->oh_heapsizer);
487295484Semaste		WRITE_OPT64(oh->oh_heapsizec);
488295484Semaste	}
489295484Semaste	WRITE_OPT32(oh->oh_ldrflags);
490295484Semaste	WRITE_OPT32(oh->oh_ndatadir);
491295484Semaste
492295484Semaste	/*
493295484Semaste	 * Write the Data Directories.
494295484Semaste	 */
495295484Semaste
496295484Semaste	if (oh->oh_ndatadir > 0) {
497295484Semaste		if (pe->pe_dd == NULL) {
498295484Semaste			if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
499295484Semaste				errno = ENOMEM;
500295484Semaste				return (-1);
501295484Semaste			}
502295484Semaste			pe->pe_dd = dd;
503295484Semaste			dd->dd_total = PE_DD_MAX;
504295484Semaste		} else
505295484Semaste			dd = pe->pe_dd;
506295484Semaste
507295484Semaste		assert(oh->oh_ndatadir <= PE_DD_MAX);
508295484Semaste
509295484Semaste		if (reloc) {
510295484Semaste			dd->dd_e[PE_DD_BASERELOC].de_addr = reloc_rva;
511295484Semaste			dd->dd_e[PE_DD_BASERELOC].de_size = reloc_sz;
512295484Semaste		}
513295484Semaste
514295484Semaste		for (i = 0; (uint32_t) i < dd->dd_total; i++) {
515295484Semaste			WRITE_OPT32(dd->dd_e[i].de_addr);
516295484Semaste			WRITE_OPT32(dd->dd_e[i].de_size);
517295484Semaste		}
518295484Semaste	}
519295484Semaste
520295484Semaste	/* Pad the remaining bytes in the Optional header, if any. */
521295484Semaste	if (ch->ch_optsize > p) {
522295484Semaste		if (libpe_pad(pe, ch->ch_optsize - p) < 0) {
523295484Semaste			errno = EIO;
524295484Semaste			return (-1);
525295484Semaste		}
526295484Semaste	}
527295484Semaste
528295484Semasteopt_done:
529295484Semaste	off += ch->ch_optsize;
530295484Semaste	pe->pe_flags &= ~LIBPE_F_DIRTY_OPT_HEADER;
531295484Semaste	pe->pe_flags &= ~LIBPE_F_BAD_OPT_HEADER;
532295484Semaste	pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
533295484Semaste
534295484Semaste	return (off);
535295484Semaste}
536