2 * Copyright (c) 2016 Kai Wang
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/param.h>
37 ELFTC_VCSID("$Id: pe.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
39 /* Convert ELF object to Portable Executable (PE). */
41 create_pe(struct elfcopy *ecp, int ifd, int ofd)
59 if (ecp->otf == ETF_EFI || ecp->oem == EM_X86_64)
64 if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
65 errx(EXIT_FAILURE, "elf_begin() failed: %s",
68 if (gelf_getehdr(e, &eh) == NULL)
69 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
72 if (elf_getshstrndx(ecp->ein, &indx) == 0)
73 errx(EXIT_FAILURE, "elf_getshstrndx() failed: %s",
76 if ((pe = pe_init(ofd, PE_C_WRITE, po)) == NULL)
77 err(EXIT_FAILURE, "pe_init() failed");
79 /* Setup PE COFF header. */
80 memset(&pch, 0, sizeof(pch));
83 pch.ch_machine = IMAGE_FILE_MACHINE_I386;
86 pch.ch_machine = IMAGE_FILE_MACHINE_AMD64;
89 pch.ch_machine = IMAGE_FILE_MACHINE_UNKNOWN;
92 pch.ch_timestamp = (uint32_t) time(NULL);
93 if (pe_update_coff_header(pe, &pch) < 0)
94 err(EXIT_FAILURE, "pe_update_coff_header() failed");
96 /* Setup PE optional header. */
97 memset(&poh, 0, sizeof(poh));
98 if (ecp->otf == ETF_EFI)
99 poh.oh_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
100 poh.oh_entry = (uint32_t) eh.e_entry;
103 * Default section alignment and file alignment. (Here the
104 * section alignment is set to the default page size of the
105 * archs supported. We should use different section alignment
106 * for some arch. (e.g. IA64)
108 poh.oh_secalign = 0x1000;
109 poh.oh_filealign = 0x200;
113 while ((scn = elf_nextscn(e, scn)) != NULL) {
116 * Read in ELF section.
119 if (gelf_getshdr(scn, &sh) == NULL) {
120 warnx("gelf_getshdr() failed: %s", elf_errmsg(-1));
124 if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) ==
126 warnx("elf_strptr() failed: %s", elf_errmsg(-1));
131 /* Skip sections unneeded. */
132 if (strcmp(name, ".shstrtab") == 0 ||
133 strcmp(name, ".symtab") == 0 ||
134 strcmp(name, ".strtab") == 0)
137 if ((d = elf_getdata(scn, NULL)) == NULL) {
138 warnx("elf_getdata() failed: %s", elf_errmsg(-1));
143 if (strcmp(name, ".text") == 0) {
144 poh.oh_textbase = (uint32_t) sh.sh_addr;
145 poh.oh_textsize = (uint32_t) roundup(sh.sh_size,
148 if (po == PE_O_PE32 && strcmp(name, ".data") == 0)
149 poh.oh_database = sh.sh_addr;
150 if (sh.sh_type == SHT_NOBITS)
151 poh.oh_bsssize += (uint32_t)
152 roundup(sh.sh_size, poh.oh_filealign);
153 else if (sh.sh_flags & SHF_ALLOC)
154 poh.oh_datasize += (uint32_t)
155 roundup(sh.sh_size, poh.oh_filealign);
159 * Create PE/COFF section.
162 if ((ps = pe_newscn(pe)) == NULL) {
163 warn("pe_newscn() failed");
168 * Setup PE/COFF section header. The section name is not
169 * NUL-terminated if its length happens to be 8. Long
170 * section name should be truncated for PE image according
171 * to the PE/COFF specification.
173 memset(&psh, 0, sizeof(psh));
174 strncpy(psh.sh_name, name, sizeof(psh.sh_name));
175 psh.sh_addr = sh.sh_addr;
176 psh.sh_virtsize = sh.sh_size;
177 if (sh.sh_type != SHT_NOBITS)
178 psh.sh_rawsize = sh.sh_size;
180 psh.sh_char |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
183 * Translate ELF section flags to PE/COFF section flags.
185 psh.sh_char |= IMAGE_SCN_MEM_READ;
186 if (sh.sh_flags & SHF_WRITE)
187 psh.sh_char |= IMAGE_SCN_MEM_WRITE;
188 if (sh.sh_flags & SHF_EXECINSTR)
189 psh.sh_char |= IMAGE_SCN_MEM_EXECUTE |
191 if ((sh.sh_flags & SHF_ALLOC) && (psh.sh_char & 0xF0) == 0)
192 psh.sh_char |= IMAGE_SCN_CNT_INITIALIZED_DATA;
193 for (i = 0xE; i > 0; i--) {
194 if (sh.sh_addralign & (1U << (i - 1))) {
195 psh.sh_char |= i << 20;
200 /* Mark relocation section "discardable". */
201 if (strcmp(name, ".reloc") == 0)
202 psh.sh_char |= IMAGE_SCN_MEM_DISCARDABLE;
204 if (pe_update_section_header(ps, &psh) < 0) {
205 warn("pe_update_section_header() failed");
209 /* Copy section content. */
210 if ((pb = pe_newbuffer(ps)) == NULL) {
211 warn("pe_newbuffer() failed");
216 pb->pb_size = sh.sh_size;
217 pb->pb_buf = d->d_buf;
219 elferr = elf_errno();
221 warnx("elf_nextscn() failed: %s", elf_errmsg(elferr));
223 /* Update PE optional header. */
224 if (pe_update_opt_header(pe, &poh) < 0)
225 err(EXIT_FAILURE, "pe_update_opt_header() failed");
227 /* Write out PE/COFF object. */
228 if (pe_update(pe) < 0)
229 err(EXIT_FAILURE, "pe_update() failed");