Path: blob/main/contrib/elftoolchain/elfcopy/pe.c
107228 views
/*-1* Copyright (c) 2016 Kai Wang2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/param.h>27#include <err.h>28#include <gelf.h>29#include <libpe.h>30#include <stdlib.h>31#include <string.h>32#include <time.h>3334#include "elfcopy.h"3536ELFTC_VCSID("$Id: pe.c 3508 2016-12-27 06:19:39Z kaiwang27 $");3738/* Convert ELF object to Portable Executable (PE). */39void40create_pe(struct elfcopy *ecp, int ifd, int ofd)41{42Elf *e;43Elf_Scn *scn;44Elf_Data *d;45GElf_Ehdr eh;46GElf_Shdr sh;47PE *pe;48PE_Scn *ps;49PE_SecHdr psh;50PE_CoffHdr pch;51PE_OptHdr poh;52PE_Object po;53PE_Buffer *pb;54const char *name;55size_t indx;56time_t timestamp;57int elferr;5859if (ecp->otf == ETF_EFI || ecp->oem == EM_X86_64)60po = PE_O_PE32P;61else62po = PE_O_PE32;6364if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)65errx(EXIT_FAILURE, "elf_begin() failed: %s",66elf_errmsg(-1));6768if (gelf_getehdr(e, &eh) == NULL)69errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",70elf_errmsg(-1));7172if (elf_getshstrndx(e, &indx) == 0)73errx(EXIT_FAILURE, "elf_getshstrndx() failed: %s",74elf_errmsg(-1));7576if ((pe = pe_init(ofd, PE_C_WRITE, po)) == NULL)77err(EXIT_FAILURE, "pe_init() failed");7879/* Setup PE COFF header. */80memset(&pch, 0, sizeof(pch));81switch (ecp->oem) {82case EM_386:83pch.ch_machine = IMAGE_FILE_MACHINE_I386;84break;85case EM_X86_64:86pch.ch_machine = IMAGE_FILE_MACHINE_AMD64;87break;88default:89pch.ch_machine = IMAGE_FILE_MACHINE_UNKNOWN;90break;91}92if (elftc_timestamp(×tamp) != 0)93err(EXIT_FAILURE, "elftc_timestamp");94pch.ch_timestamp = (uint32_t) timestamp;95if (pe_update_coff_header(pe, &pch) < 0)96err(EXIT_FAILURE, "pe_update_coff_header() failed");9798/* Setup PE optional header. */99memset(&poh, 0, sizeof(poh));100if (ecp->otf == ETF_EFI)101poh.oh_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;102poh.oh_entry = (uint32_t) eh.e_entry;103104/*105* Default section alignment and file alignment. (Here the106* section alignment is set to the default page size of the107* archs supported. We should use different section alignment108* for some arch. (e.g. IA64)109*/110poh.oh_secalign = 0x1000;111poh.oh_filealign = 0x200;112113/* Copy sections. */114scn = NULL;115while ((scn = elf_nextscn(e, scn)) != NULL) {116117/*118* Read in ELF section.119*/120121if (gelf_getshdr(scn, &sh) == NULL) {122warnx("gelf_getshdr() failed: %s", elf_errmsg(-1));123(void) elf_errno();124continue;125}126if ((name = elf_strptr(e, indx, sh.sh_name)) ==127NULL) {128warnx("elf_strptr() failed: %s", elf_errmsg(-1));129(void) elf_errno();130continue;131}132133/* Skip sections unneeded. */134if (strcmp(name, ".shstrtab") == 0 ||135strcmp(name, ".symtab") == 0 ||136strcmp(name, ".strtab") == 0)137continue;138139if ((d = elf_getdata(scn, NULL)) == NULL) {140warnx("elf_getdata() failed: %s", elf_errmsg(-1));141(void) elf_errno();142continue;143}144145if (strcmp(name, ".text") == 0) {146poh.oh_textbase = (uint32_t) sh.sh_addr;147poh.oh_textsize = (uint32_t) roundup(sh.sh_size,148poh.oh_filealign);149} else {150if (po == PE_O_PE32 && strcmp(name, ".data") == 0)151poh.oh_database = sh.sh_addr;152if (sh.sh_type == SHT_NOBITS)153poh.oh_bsssize += (uint32_t)154roundup(sh.sh_size, poh.oh_filealign);155else if (sh.sh_flags & SHF_ALLOC)156poh.oh_datasize += (uint32_t)157roundup(sh.sh_size, poh.oh_filealign);158}159160/*161* Create PE/COFF section.162*/163164if ((ps = pe_newscn(pe)) == NULL) {165warn("pe_newscn() failed");166continue;167}168169/*170* Setup PE/COFF section header. The section name is not171* NUL-terminated if its length happens to be 8. Long172* section name should be truncated for PE image according173* to the PE/COFF specification.174*/175memset(&psh, 0, sizeof(psh));176strncpy(psh.sh_name, name, sizeof(psh.sh_name));177psh.sh_addr = sh.sh_addr;178psh.sh_virtsize = sh.sh_size;179if (sh.sh_type != SHT_NOBITS)180psh.sh_rawsize = roundup(sh.sh_size, poh.oh_filealign);181else182psh.sh_char |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;183184/*185* Translate ELF section flags to PE/COFF section flags.186*/187psh.sh_char |= IMAGE_SCN_MEM_READ;188if (sh.sh_flags & SHF_WRITE)189psh.sh_char |= IMAGE_SCN_MEM_WRITE;190if (sh.sh_flags & SHF_EXECINSTR)191psh.sh_char |= IMAGE_SCN_MEM_EXECUTE |192IMAGE_SCN_CNT_CODE;193if ((sh.sh_flags & SHF_ALLOC) && (psh.sh_char & 0xF0) == 0)194psh.sh_char |= IMAGE_SCN_CNT_INITIALIZED_DATA;195196/* Mark relocation section "discardable". */197if (strcmp(name, ".reloc") == 0)198psh.sh_char |= IMAGE_SCN_MEM_DISCARDABLE;199200if (pe_update_section_header(ps, &psh) < 0) {201warn("pe_update_section_header() failed");202continue;203}204205/* Copy section content. */206if ((pb = pe_newbuffer(ps)) == NULL) {207warn("pe_newbuffer() failed");208continue;209}210pb->pb_align = 1;211pb->pb_off = 0;212if (sh.sh_type != SHT_NOBITS) {213pb->pb_size = roundup(sh.sh_size, poh.oh_filealign);214if ((pb->pb_buf = calloc(1, pb->pb_size)) == NULL) {215warn("calloc failed");216continue;217}218memcpy(pb->pb_buf, d->d_buf, sh.sh_size);219}220}221elferr = elf_errno();222if (elferr != 0)223warnx("elf_nextscn() failed: %s", elf_errmsg(elferr));224225/* Update PE optional header. */226if (pe_update_opt_header(pe, &poh) < 0)227err(EXIT_FAILURE, "pe_update_opt_header() failed");228229/* Write out PE/COFF object. */230if (pe_update(pe) < 0)231err(EXIT_FAILURE, "pe_update() failed");232233pe_finish(pe);234elf_end(e);235}236237238