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