1*839529caSEd Maste /*-
2*839529caSEd Maste * Copyright (c) 2015 Kai Wang
3*839529caSEd Maste * All rights reserved.
4*839529caSEd Maste *
5*839529caSEd Maste * Redistribution and use in source and binary forms, with or without
6*839529caSEd Maste * modification, are permitted provided that the following conditions
7*839529caSEd Maste * are met:
8*839529caSEd Maste * 1. Redistributions of source code must retain the above copyright
9*839529caSEd Maste * notice, this list of conditions and the following disclaimer.
10*839529caSEd Maste * 2. Redistributions in binary form must reproduce the above copyright
11*839529caSEd Maste * notice, this list of conditions and the following disclaimer in the
12*839529caSEd Maste * documentation and/or other materials provided with the distribution.
13*839529caSEd Maste *
14*839529caSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*839529caSEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*839529caSEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*839529caSEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*839529caSEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*839529caSEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*839529caSEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*839529caSEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*839529caSEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*839529caSEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*839529caSEd Maste * SUCH DAMAGE.
25*839529caSEd Maste */
26*839529caSEd Maste
27*839529caSEd Maste #include <sys/param.h>
28*839529caSEd Maste #include <assert.h>
29*839529caSEd Maste #include <errno.h>
30*839529caSEd Maste #include <stdlib.h>
31*839529caSEd Maste #include <string.h>
32*839529caSEd Maste #include <time.h>
33*839529caSEd Maste #include <unistd.h>
34*839529caSEd Maste
35*839529caSEd Maste #include "_libpe.h"
36*839529caSEd Maste
37*839529caSEd Maste ELFTC_VCSID("$Id: libpe_coff.c 3326 2016-01-16 17:46:17Z kaiwang27 $");
38*839529caSEd Maste
39*839529caSEd Maste int
libpe_parse_coff_header(PE * pe,char * hdr)40*839529caSEd Maste libpe_parse_coff_header(PE *pe, char *hdr)
41*839529caSEd Maste {
42*839529caSEd Maste char tmp[128];
43*839529caSEd Maste PE_CoffHdr *ch;
44*839529caSEd Maste PE_OptHdr *oh;
45*839529caSEd Maste PE_DataDir *dd;
46*839529caSEd Maste unsigned p, r, s;
47*839529caSEd Maste int i;
48*839529caSEd Maste
49*839529caSEd Maste if ((ch = malloc(sizeof(PE_CoffHdr))) == NULL) {
50*839529caSEd Maste errno = ENOMEM;
51*839529caSEd Maste return (-1);
52*839529caSEd Maste }
53*839529caSEd Maste
54*839529caSEd Maste PE_READ16(hdr, ch->ch_machine);
55*839529caSEd Maste PE_READ16(hdr, ch->ch_nsec);
56*839529caSEd Maste PE_READ32(hdr, ch->ch_timestamp);
57*839529caSEd Maste PE_READ32(hdr, ch->ch_symptr);
58*839529caSEd Maste PE_READ32(hdr, ch->ch_nsym);
59*839529caSEd Maste PE_READ16(hdr, ch->ch_optsize);
60*839529caSEd Maste PE_READ16(hdr, ch->ch_char);
61*839529caSEd Maste
62*839529caSEd Maste pe->pe_ch = ch;
63*839529caSEd Maste
64*839529caSEd Maste /*
65*839529caSEd Maste * The Optional header is omitted for object files.
66*839529caSEd Maste */
67*839529caSEd Maste if (ch->ch_optsize == 0)
68*839529caSEd Maste return (libpe_parse_section_headers(pe));
69*839529caSEd Maste
70*839529caSEd Maste if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
71*839529caSEd Maste errno = ENOMEM;
72*839529caSEd Maste return (-1);
73*839529caSEd Maste }
74*839529caSEd Maste pe->pe_oh = oh;
75*839529caSEd Maste
76*839529caSEd Maste #define READ_OPT(n) \
77*839529caSEd Maste do { \
78*839529caSEd Maste /* \
79*839529caSEd Maste * Since the Optional Header size is variable, we must \
80*839529caSEd Maste * check if the requested read size will overrun the \
81*839529caSEd Maste * remaining header bytes. \
82*839529caSEd Maste */ \
83*839529caSEd Maste if (p + (n) > ch->ch_optsize) { \
84*839529caSEd Maste /* Consume the "extra" bytes */ \
85*839529caSEd Maste r = ch->ch_optsize - p; \
86*839529caSEd Maste if (read(pe->pe_fd, tmp, r) != (ssize_t) r) { \
87*839529caSEd Maste pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;\
88*839529caSEd Maste return (0); \
89*839529caSEd Maste } \
90*839529caSEd Maste return (libpe_parse_section_headers(pe)); \
91*839529caSEd Maste } \
92*839529caSEd Maste if (read(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) { \
93*839529caSEd Maste pe->pe_flags |= LIBPE_F_BAD_OPT_HEADER; \
94*839529caSEd Maste return (0); \
95*839529caSEd Maste } \
96*839529caSEd Maste p += (n); \
97*839529caSEd Maste } while (0)
98*839529caSEd Maste #define READ_OPT8(v) do { READ_OPT(1); (v) = *tmp; } while(0)
99*839529caSEd Maste #define READ_OPT16(v) do { READ_OPT(2); (v) = le16dec(tmp); } while(0)
100*839529caSEd Maste #define READ_OPT32(v) do { READ_OPT(4); (v) = le32dec(tmp); } while(0)
101*839529caSEd Maste #define READ_OPT64(v) do { READ_OPT(8); (v) = le64dec(tmp); } while(0)
102*839529caSEd Maste
103*839529caSEd Maste /*
104*839529caSEd Maste * Read in the Optional header. Size of some fields are depending
105*839529caSEd Maste * on the PE format specified by the oh_magic field. (PE32 or PE32+)
106*839529caSEd Maste */
107*839529caSEd Maste
108*839529caSEd Maste p = 0;
109*839529caSEd Maste READ_OPT16(oh->oh_magic);
110*839529caSEd Maste if (oh->oh_magic == PE_FORMAT_32P)
111*839529caSEd Maste pe->pe_obj = PE_O_PE32P;
112*839529caSEd Maste READ_OPT8(oh->oh_ldvermajor);
113*839529caSEd Maste READ_OPT8(oh->oh_ldverminor);
114*839529caSEd Maste READ_OPT32(oh->oh_textsize);
115*839529caSEd Maste READ_OPT32(oh->oh_datasize);
116*839529caSEd Maste READ_OPT32(oh->oh_bsssize);
117*839529caSEd Maste READ_OPT32(oh->oh_entry);
118*839529caSEd Maste READ_OPT32(oh->oh_textbase);
119*839529caSEd Maste if (oh->oh_magic != PE_FORMAT_32P) {
120*839529caSEd Maste READ_OPT32(oh->oh_database);
121*839529caSEd Maste READ_OPT32(oh->oh_imgbase);
122*839529caSEd Maste } else
123*839529caSEd Maste READ_OPT64(oh->oh_imgbase);
124*839529caSEd Maste READ_OPT32(oh->oh_secalign);
125*839529caSEd Maste READ_OPT32(oh->oh_filealign);
126*839529caSEd Maste READ_OPT16(oh->oh_osvermajor);
127*839529caSEd Maste READ_OPT16(oh->oh_osverminor);
128*839529caSEd Maste READ_OPT16(oh->oh_imgvermajor);
129*839529caSEd Maste READ_OPT16(oh->oh_imgverminor);
130*839529caSEd Maste READ_OPT16(oh->oh_subvermajor);
131*839529caSEd Maste READ_OPT16(oh->oh_subverminor);
132*839529caSEd Maste READ_OPT32(oh->oh_win32ver);
133*839529caSEd Maste READ_OPT32(oh->oh_imgsize);
134*839529caSEd Maste READ_OPT32(oh->oh_hdrsize);
135*839529caSEd Maste READ_OPT32(oh->oh_checksum);
136*839529caSEd Maste READ_OPT16(oh->oh_subsystem);
137*839529caSEd Maste READ_OPT16(oh->oh_dllchar);
138*839529caSEd Maste if (oh->oh_magic != PE_FORMAT_32P) {
139*839529caSEd Maste READ_OPT32(oh->oh_stacksizer);
140*839529caSEd Maste READ_OPT32(oh->oh_stacksizec);
141*839529caSEd Maste READ_OPT32(oh->oh_heapsizer);
142*839529caSEd Maste READ_OPT32(oh->oh_heapsizec);
143*839529caSEd Maste } else {
144*839529caSEd Maste READ_OPT64(oh->oh_stacksizer);
145*839529caSEd Maste READ_OPT64(oh->oh_stacksizec);
146*839529caSEd Maste READ_OPT64(oh->oh_heapsizer);
147*839529caSEd Maste READ_OPT64(oh->oh_heapsizec);
148*839529caSEd Maste }
149*839529caSEd Maste READ_OPT32(oh->oh_ldrflags);
150*839529caSEd Maste READ_OPT32(oh->oh_ndatadir);
151*839529caSEd Maste
152*839529caSEd Maste /*
153*839529caSEd Maste * Read in the Data Directories.
154*839529caSEd Maste */
155*839529caSEd Maste
156*839529caSEd Maste if (oh->oh_ndatadir > 0) {
157*839529caSEd Maste if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
158*839529caSEd Maste errno = ENOMEM;
159*839529caSEd Maste return (-1);
160*839529caSEd Maste }
161*839529caSEd Maste pe->pe_dd = dd;
162*839529caSEd Maste
163*839529caSEd Maste dd->dd_total = oh->oh_ndatadir < PE_DD_MAX ? oh->oh_ndatadir :
164*839529caSEd Maste PE_DD_MAX;
165*839529caSEd Maste
166*839529caSEd Maste for (i = 0; (uint32_t) i < dd->dd_total; i++) {
167*839529caSEd Maste READ_OPT32(dd->dd_e[i].de_addr);
168*839529caSEd Maste READ_OPT32(dd->dd_e[i].de_size);
169*839529caSEd Maste }
170*839529caSEd Maste }
171*839529caSEd Maste
172*839529caSEd Maste /* Consume the remaining bytes in the Optional header, if any. */
173*839529caSEd Maste if (ch->ch_optsize > p) {
174*839529caSEd Maste r = ch->ch_optsize - p;
175*839529caSEd Maste for (; r > 0; r -= s) {
176*839529caSEd Maste s = r > sizeof(tmp) ? sizeof(tmp) : r;
177*839529caSEd Maste if (read(pe->pe_fd, tmp, s) != (ssize_t) s) {
178*839529caSEd Maste pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;
179*839529caSEd Maste return (0);
180*839529caSEd Maste }
181*839529caSEd Maste }
182*839529caSEd Maste }
183*839529caSEd Maste
184*839529caSEd Maste return (libpe_parse_section_headers(pe));
185*839529caSEd Maste }
186*839529caSEd Maste
187*839529caSEd Maste off_t
libpe_write_pe_header(PE * pe,off_t off)188*839529caSEd Maste libpe_write_pe_header(PE *pe, off_t off)
189*839529caSEd Maste {
190*839529caSEd Maste char tmp[4];
191*839529caSEd Maste
192*839529caSEd Maste if (pe->pe_cmd == PE_C_RDWR &&
193*839529caSEd Maste (pe->pe_flags & LIBPE_F_BAD_PE_HEADER) == 0) {
194*839529caSEd Maste assert(pe->pe_dh != NULL);
195*839529caSEd Maste off = lseek(pe->pe_fd, (off_t) pe->pe_dh->dh_lfanew + 4,
196*839529caSEd Maste SEEK_SET);
197*839529caSEd Maste return (off);
198*839529caSEd Maste }
199*839529caSEd Maste
200*839529caSEd Maste /*
201*839529caSEd Maste * PE Header should to be aligned on 8-byte boundary according to
202*839529caSEd Maste * the PE/COFF specification.
203*839529caSEd Maste */
204*839529caSEd Maste if ((off = libpe_align(pe, off, 8)) < 0)
205*839529caSEd Maste return (-1);
206*839529caSEd Maste
207*839529caSEd Maste le32enc(tmp, PE_SIGNATURE);
208*839529caSEd Maste if (write(pe->pe_fd, tmp, sizeof(tmp)) != (ssize_t) sizeof(tmp)) {
209*839529caSEd Maste errno = EIO;
210*839529caSEd Maste return (-1);
211*839529caSEd Maste }
212*839529caSEd Maste
213*839529caSEd Maste off += 4;
214*839529caSEd Maste
215*839529caSEd Maste pe->pe_flags &= ~LIBPE_F_BAD_PE_HEADER;
216*839529caSEd Maste
217*839529caSEd Maste /* Trigger rewrite for the following headers. */
218*839529caSEd Maste pe->pe_flags |= LIBPE_F_DIRTY_COFF_HEADER;
219*839529caSEd Maste pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
220*839529caSEd Maste
221*839529caSEd Maste return (off);
222*839529caSEd Maste }
223*839529caSEd Maste
224*839529caSEd Maste off_t
libpe_write_coff_header(PE * pe,off_t off)225*839529caSEd Maste libpe_write_coff_header(PE *pe, off_t off)
226*839529caSEd Maste {
227*839529caSEd Maste char tmp[128], *hdr;
228*839529caSEd Maste PE_CoffHdr *ch;
229*839529caSEd Maste PE_DataDir *dd;
230*839529caSEd Maste PE_OptHdr *oh;
231*839529caSEd Maste PE_Scn *ps;
232*839529caSEd Maste PE_SecHdr *sh;
233*839529caSEd Maste unsigned p;
234*839529caSEd Maste uint32_t reloc_rva, reloc_sz;
235*839529caSEd Maste int i, reloc;
236*839529caSEd Maste
237*839529caSEd Maste reloc = 0;
238*839529caSEd Maste reloc_rva = reloc_sz = 0;
239*839529caSEd Maste
240*839529caSEd Maste if (pe->pe_cmd == PE_C_RDWR) {
241*839529caSEd Maste assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
242*839529caSEd Maste
243*839529caSEd Maste if ((pe->pe_flags & LIBPE_F_DIRTY_COFF_HEADER) == 0 &&
244*839529caSEd Maste (pe->pe_flags & LIBPE_F_BAD_COFF_HEADER) == 0) {
245*839529caSEd Maste if (lseek(pe->pe_fd, (off_t) sizeof(PE_CoffHdr),
246*839529caSEd Maste SEEK_CUR) < 0) {
247*839529caSEd Maste errno = EIO;
248*839529caSEd Maste return (-1);
249*839529caSEd Maste }
250*839529caSEd Maste off += sizeof(PE_CoffHdr);
251*839529caSEd Maste assert(pe->pe_ch != NULL);
252*839529caSEd Maste ch = pe->pe_ch;
253*839529caSEd Maste goto coff_done;
254*839529caSEd Maste }
255*839529caSEd Maste
256*839529caSEd Maste /* lseek(2) to the offset of the COFF header. */
257*839529caSEd Maste if (lseek(pe->pe_fd, off, SEEK_SET) < 0) {
258*839529caSEd Maste errno = EIO;
259*839529caSEd Maste return (-1);
260*839529caSEd Maste }
261*839529caSEd Maste }
262*839529caSEd Maste
263*839529caSEd Maste if (pe->pe_ch == NULL) {
264*839529caSEd Maste if ((ch = calloc(1, sizeof(PE_CoffHdr))) == NULL) {
265*839529caSEd Maste errno = ENOMEM;
266*839529caSEd Maste return (-1);
267*839529caSEd Maste }
268*839529caSEd Maste pe->pe_ch = ch;
269*839529caSEd Maste
270*839529caSEd Maste /*
271*839529caSEd Maste * Default value for ch_machine if not provided by the
272*839529caSEd Maste * application.
273*839529caSEd Maste */
274*839529caSEd Maste if (pe->pe_obj == PE_O_PE32P)
275*839529caSEd Maste ch->ch_machine = IMAGE_FILE_MACHINE_AMD64;
276*839529caSEd Maste else
277*839529caSEd Maste ch->ch_machine = IMAGE_FILE_MACHINE_I386;
278*839529caSEd Maste
279*839529caSEd Maste } else
280*839529caSEd Maste ch = pe->pe_ch;
281*839529caSEd Maste
282*839529caSEd Maste if (!ch->ch_timestamp)
283*839529caSEd Maste ch->ch_timestamp = time(NULL);
284*839529caSEd Maste
285*839529caSEd Maste if (pe->pe_obj == PE_O_PE32) {
286*839529caSEd Maste if (!ch->ch_optsize)
287*839529caSEd Maste ch->ch_optsize = PE_COFF_OPT_SIZE_32;
288*839529caSEd Maste ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
289*839529caSEd Maste IMAGE_FILE_32BIT_MACHINE;
290*839529caSEd Maste } else if (pe->pe_obj == PE_O_PE32P) {
291*839529caSEd Maste if (!ch->ch_optsize)
292*839529caSEd Maste ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
293*839529caSEd Maste ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
294*839529caSEd Maste IMAGE_FILE_LARGE_ADDRESS_AWARE;
295*839529caSEd Maste } else
296*839529caSEd Maste ch->ch_optsize = 0;
297*839529caSEd Maste
298*839529caSEd Maste /*
299*839529caSEd Maste * COFF line number is deprecated by the PE/COFF
300*839529caSEd Maste * specification. COFF symbol table is deprecated
301*839529caSEd Maste * for executables.
302*839529caSEd Maste */
303*839529caSEd Maste ch->ch_char |= IMAGE_FILE_LINE_NUMS_STRIPPED;
304*839529caSEd Maste if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P)
305*839529caSEd Maste ch->ch_char |= IMAGE_FILE_LOCAL_SYMS_STRIPPED;
306*839529caSEd Maste
307*839529caSEd Maste ch->ch_nsec = pe->pe_nscn;
308*839529caSEd Maste
309*839529caSEd Maste STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
310*839529caSEd Maste sh = &ps->ps_sh;
311*839529caSEd Maste
312*839529caSEd Maste if (ps->ps_ndx == 0xFFFFFFFFU) {
313*839529caSEd Maste ch->ch_symptr = sh->sh_rawptr;
314*839529caSEd Maste ch->ch_nsym = pe->pe_nsym;
315*839529caSEd Maste }
316*839529caSEd Maste
317*839529caSEd Maste if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P) {
318*839529caSEd Maste if (ps->ps_ndx == (0xFFFF0000 | PE_DD_BASERELOC) ||
319*839529caSEd Maste strncmp(sh->sh_name, ".reloc", strlen(".reloc")) ==
320*839529caSEd Maste 0) {
321*839529caSEd Maste reloc = 1;
322*839529caSEd Maste reloc_rva = sh->sh_addr;
323*839529caSEd Maste reloc_sz = sh->sh_virtsize;
324*839529caSEd Maste }
325*839529caSEd Maste }
326*839529caSEd Maste }
327*839529caSEd Maste
328*839529caSEd Maste if (!reloc)
329*839529caSEd Maste ch->ch_char |= IMAGE_FILE_RELOCS_STRIPPED;
330*839529caSEd Maste
331*839529caSEd Maste if (pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) {
332*839529caSEd Maste if (pe->pe_obj == PE_O_PE32)
333*839529caSEd Maste ch->ch_optsize = PE_COFF_OPT_SIZE_32;
334*839529caSEd Maste else if (pe->pe_obj == PE_O_PE32P)
335*839529caSEd Maste ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
336*839529caSEd Maste else
337*839529caSEd Maste ch->ch_optsize = 0;
338*839529caSEd Maste }
339*839529caSEd Maste
340*839529caSEd Maste /*
341*839529caSEd Maste * Write the COFF header.
342*839529caSEd Maste */
343*839529caSEd Maste hdr = tmp;
344*839529caSEd Maste PE_WRITE16(hdr, ch->ch_machine);
345*839529caSEd Maste PE_WRITE16(hdr, ch->ch_nsec);
346*839529caSEd Maste PE_WRITE32(hdr, ch->ch_timestamp);
347*839529caSEd Maste PE_WRITE32(hdr, ch->ch_symptr);
348*839529caSEd Maste PE_WRITE32(hdr, ch->ch_nsym);
349*839529caSEd Maste PE_WRITE16(hdr, ch->ch_optsize);
350*839529caSEd Maste PE_WRITE16(hdr, ch->ch_char);
351*839529caSEd Maste if (write(pe->pe_fd, tmp, sizeof(PE_CoffHdr)) !=
352*839529caSEd Maste (ssize_t) sizeof(PE_CoffHdr)) {
353*839529caSEd Maste errno = EIO;
354*839529caSEd Maste return (-1);
355*839529caSEd Maste }
356*839529caSEd Maste
357*839529caSEd Maste coff_done:
358*839529caSEd Maste off += sizeof(PE_CoffHdr);
359*839529caSEd Maste pe->pe_flags &= ~LIBPE_F_DIRTY_COFF_HEADER;
360*839529caSEd Maste pe->pe_flags &= ~LIBPE_F_BAD_COFF_HEADER;
361*839529caSEd Maste pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
362*839529caSEd Maste
363*839529caSEd Maste if (ch->ch_optsize == 0)
364*839529caSEd Maste return (off);
365*839529caSEd Maste
366*839529caSEd Maste /*
367*839529caSEd Maste * Write the Optional header.
368*839529caSEd Maste */
369*839529caSEd Maste
370*839529caSEd Maste if (pe->pe_cmd == PE_C_RDWR) {
371*839529caSEd Maste if ((pe->pe_flags & LIBPE_F_DIRTY_OPT_HEADER) == 0 &&
372*839529caSEd Maste (pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) == 0) {
373*839529caSEd Maste if (lseek(pe->pe_fd, (off_t) ch->ch_optsize,
374*839529caSEd Maste SEEK_CUR) < 0) {
375*839529caSEd Maste errno = EIO;
376*839529caSEd Maste return (-1);
377*839529caSEd Maste }
378*839529caSEd Maste off += ch->ch_optsize;
379*839529caSEd Maste return (off);
380*839529caSEd Maste }
381*839529caSEd Maste
382*839529caSEd Maste }
383*839529caSEd Maste
384*839529caSEd Maste if (pe->pe_oh == NULL) {
385*839529caSEd Maste if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
386*839529caSEd Maste errno = ENOMEM;
387*839529caSEd Maste return (-1);
388*839529caSEd Maste }
389*839529caSEd Maste pe->pe_oh = oh;
390*839529caSEd Maste } else
391*839529caSEd Maste oh = pe->pe_oh;
392*839529caSEd Maste
393*839529caSEd Maste if (pe->pe_obj == PE_O_PE32)
394*839529caSEd Maste oh->oh_magic = PE_FORMAT_32;
395*839529caSEd Maste else
396*839529caSEd Maste oh->oh_magic = PE_FORMAT_32P;
397*839529caSEd Maste
398*839529caSEd Maste /*
399*839529caSEd Maste * LinkerVersion should not be less than 2.5, which will cause
400*839529caSEd Maste * Windows to complain the executable is invalid in some case.
401*839529caSEd Maste * By default we set LinkerVersion to 2.22 (binutils 2.22)
402*839529caSEd Maste */
403*839529caSEd Maste if (!oh->oh_ldvermajor && !oh->oh_ldverminor) {
404*839529caSEd Maste oh->oh_ldvermajor = 2;
405*839529caSEd Maste oh->oh_ldverminor = 22;
406*839529caSEd Maste }
407*839529caSEd Maste
408*839529caSEd Maste /*
409*839529caSEd Maste * The library always tries to write out all 16 data directories
410*839529caSEd Maste * but the actual data dir written will depend on ch_optsize.
411*839529caSEd Maste */
412*839529caSEd Maste oh->oh_ndatadir = PE_DD_MAX;
413*839529caSEd Maste
414*839529caSEd Maste if (!oh->oh_filealign)
415*839529caSEd Maste oh->oh_filealign = 0x200;
416*839529caSEd Maste if (!oh->oh_secalign)
417*839529caSEd Maste oh->oh_secalign = 0x1000;
418*839529caSEd Maste oh->oh_hdrsize = roundup(off + ch->ch_optsize + pe->pe_nscn *
419*839529caSEd Maste sizeof(PE_SecHdr), oh->oh_filealign);
420*839529caSEd Maste oh->oh_imgsize = roundup(pe->pe_rvamax, oh->oh_secalign);
421*839529caSEd Maste
422*839529caSEd Maste #define WRITE_OPT(n) \
423*839529caSEd Maste do { \
424*839529caSEd Maste /* \
425*839529caSEd Maste * Since the Optional Header size is variable, we must \
426*839529caSEd Maste * check if the requested write size will overrun the \
427*839529caSEd Maste * remaining header bytes. \
428*839529caSEd Maste */ \
429*839529caSEd Maste if (p + (n) > ch->ch_optsize) { \
430*839529caSEd Maste /* Pad the "extra" bytes */ \
431*839529caSEd Maste if (libpe_pad(pe, ch->ch_optsize - p) < 0) { \
432*839529caSEd Maste errno = EIO; \
433*839529caSEd Maste return (-1); \
434*839529caSEd Maste } \
435*839529caSEd Maste goto opt_done; \
436*839529caSEd Maste } \
437*839529caSEd Maste if (write(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) { \
438*839529caSEd Maste errno = EIO; \
439*839529caSEd Maste return (-1); \
440*839529caSEd Maste } \
441*839529caSEd Maste p += (n); \
442*839529caSEd Maste } while (0)
443*839529caSEd Maste #define WRITE_OPT8(v) do { *tmp = (v); WRITE_OPT(1); } while(0)
444*839529caSEd Maste #define WRITE_OPT16(v) do { le16enc(tmp, (v)); WRITE_OPT(2); } while(0)
445*839529caSEd Maste #define WRITE_OPT32(v) do { le32enc(tmp, (v)); WRITE_OPT(4); } while(0)
446*839529caSEd Maste #define WRITE_OPT64(v) do { le64enc(tmp, (v)); WRITE_OPT(8); } while(0)
447*839529caSEd Maste
448*839529caSEd Maste p = 0;
449*839529caSEd Maste WRITE_OPT16(oh->oh_magic);
450*839529caSEd Maste if (oh->oh_magic == PE_FORMAT_32P)
451*839529caSEd Maste pe->pe_obj = PE_O_PE32P;
452*839529caSEd Maste WRITE_OPT8(oh->oh_ldvermajor);
453*839529caSEd Maste WRITE_OPT8(oh->oh_ldverminor);
454*839529caSEd Maste WRITE_OPT32(oh->oh_textsize);
455*839529caSEd Maste WRITE_OPT32(oh->oh_datasize);
456*839529caSEd Maste WRITE_OPT32(oh->oh_bsssize);
457*839529caSEd Maste WRITE_OPT32(oh->oh_entry);
458*839529caSEd Maste WRITE_OPT32(oh->oh_textbase);
459*839529caSEd Maste if (oh->oh_magic != PE_FORMAT_32P) {
460*839529caSEd Maste WRITE_OPT32(oh->oh_database);
461*839529caSEd Maste WRITE_OPT32(oh->oh_imgbase);
462*839529caSEd Maste } else
463*839529caSEd Maste WRITE_OPT64(oh->oh_imgbase);
464*839529caSEd Maste WRITE_OPT32(oh->oh_secalign);
465*839529caSEd Maste WRITE_OPT32(oh->oh_filealign);
466*839529caSEd Maste WRITE_OPT16(oh->oh_osvermajor);
467*839529caSEd Maste WRITE_OPT16(oh->oh_osverminor);
468*839529caSEd Maste WRITE_OPT16(oh->oh_imgvermajor);
469*839529caSEd Maste WRITE_OPT16(oh->oh_imgverminor);
470*839529caSEd Maste WRITE_OPT16(oh->oh_subvermajor);
471*839529caSEd Maste WRITE_OPT16(oh->oh_subverminor);
472*839529caSEd Maste WRITE_OPT32(oh->oh_win32ver);
473*839529caSEd Maste WRITE_OPT32(oh->oh_imgsize);
474*839529caSEd Maste WRITE_OPT32(oh->oh_hdrsize);
475*839529caSEd Maste WRITE_OPT32(oh->oh_checksum);
476*839529caSEd Maste WRITE_OPT16(oh->oh_subsystem);
477*839529caSEd Maste WRITE_OPT16(oh->oh_dllchar);
478*839529caSEd Maste if (oh->oh_magic != PE_FORMAT_32P) {
479*839529caSEd Maste WRITE_OPT32(oh->oh_stacksizer);
480*839529caSEd Maste WRITE_OPT32(oh->oh_stacksizec);
481*839529caSEd Maste WRITE_OPT32(oh->oh_heapsizer);
482*839529caSEd Maste WRITE_OPT32(oh->oh_heapsizec);
483*839529caSEd Maste } else {
484*839529caSEd Maste WRITE_OPT64(oh->oh_stacksizer);
485*839529caSEd Maste WRITE_OPT64(oh->oh_stacksizec);
486*839529caSEd Maste WRITE_OPT64(oh->oh_heapsizer);
487*839529caSEd Maste WRITE_OPT64(oh->oh_heapsizec);
488*839529caSEd Maste }
489*839529caSEd Maste WRITE_OPT32(oh->oh_ldrflags);
490*839529caSEd Maste WRITE_OPT32(oh->oh_ndatadir);
491*839529caSEd Maste
492*839529caSEd Maste /*
493*839529caSEd Maste * Write the Data Directories.
494*839529caSEd Maste */
495*839529caSEd Maste
496*839529caSEd Maste if (oh->oh_ndatadir > 0) {
497*839529caSEd Maste if (pe->pe_dd == NULL) {
498*839529caSEd Maste if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
499*839529caSEd Maste errno = ENOMEM;
500*839529caSEd Maste return (-1);
501*839529caSEd Maste }
502*839529caSEd Maste pe->pe_dd = dd;
503*839529caSEd Maste dd->dd_total = PE_DD_MAX;
504*839529caSEd Maste } else
505*839529caSEd Maste dd = pe->pe_dd;
506*839529caSEd Maste
507*839529caSEd Maste assert(oh->oh_ndatadir <= PE_DD_MAX);
508*839529caSEd Maste
509*839529caSEd Maste if (reloc) {
510*839529caSEd Maste dd->dd_e[PE_DD_BASERELOC].de_addr = reloc_rva;
511*839529caSEd Maste dd->dd_e[PE_DD_BASERELOC].de_size = reloc_sz;
512*839529caSEd Maste }
513*839529caSEd Maste
514*839529caSEd Maste for (i = 0; (uint32_t) i < dd->dd_total; i++) {
515*839529caSEd Maste WRITE_OPT32(dd->dd_e[i].de_addr);
516*839529caSEd Maste WRITE_OPT32(dd->dd_e[i].de_size);
517*839529caSEd Maste }
518*839529caSEd Maste }
519*839529caSEd Maste
520*839529caSEd Maste /* Pad the remaining bytes in the Optional header, if any. */
521*839529caSEd Maste if (ch->ch_optsize > p) {
522*839529caSEd Maste if (libpe_pad(pe, ch->ch_optsize - p) < 0) {
523*839529caSEd Maste errno = EIO;
524*839529caSEd Maste return (-1);
525*839529caSEd Maste }
526*839529caSEd Maste }
527*839529caSEd Maste
528*839529caSEd Maste opt_done:
529*839529caSEd Maste off += ch->ch_optsize;
530*839529caSEd Maste pe->pe_flags &= ~LIBPE_F_DIRTY_OPT_HEADER;
531*839529caSEd Maste pe->pe_flags &= ~LIBPE_F_BAD_OPT_HEADER;
532*839529caSEd Maste pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
533*839529caSEd Maste
534*839529caSEd Maste return (off);
535*839529caSEd Maste }
536