Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/elftoolchain/elfcopy/pe.c
39536 views
1
/*-
2
* Copyright (c) 2016 Kai Wang
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
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.
13
*
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
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/param.h>
28
#include <err.h>
29
#include <gelf.h>
30
#include <libpe.h>
31
#include <stdlib.h>
32
#include <string.h>
33
#include <time.h>
34
35
#include "elfcopy.h"
36
37
ELFTC_VCSID("$Id: pe.c 3508 2016-12-27 06:19:39Z kaiwang27 $");
38
39
/* Convert ELF object to Portable Executable (PE). */
40
void
41
create_pe(struct elfcopy *ecp, int ifd, int ofd)
42
{
43
Elf *e;
44
Elf_Scn *scn;
45
Elf_Data *d;
46
GElf_Ehdr eh;
47
GElf_Shdr sh;
48
PE *pe;
49
PE_Scn *ps;
50
PE_SecHdr psh;
51
PE_CoffHdr pch;
52
PE_OptHdr poh;
53
PE_Object po;
54
PE_Buffer *pb;
55
const char *name;
56
size_t indx;
57
time_t timestamp;
58
int elferr;
59
60
if (ecp->otf == ETF_EFI || ecp->oem == EM_X86_64)
61
po = PE_O_PE32P;
62
else
63
po = PE_O_PE32;
64
65
if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
66
errx(EXIT_FAILURE, "elf_begin() failed: %s",
67
elf_errmsg(-1));
68
69
if (gelf_getehdr(e, &eh) == NULL)
70
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
71
elf_errmsg(-1));
72
73
if (elf_getshstrndx(e, &indx) == 0)
74
errx(EXIT_FAILURE, "elf_getshstrndx() failed: %s",
75
elf_errmsg(-1));
76
77
if ((pe = pe_init(ofd, PE_C_WRITE, po)) == NULL)
78
err(EXIT_FAILURE, "pe_init() failed");
79
80
/* Setup PE COFF header. */
81
memset(&pch, 0, sizeof(pch));
82
switch (ecp->oem) {
83
case EM_386:
84
pch.ch_machine = IMAGE_FILE_MACHINE_I386;
85
break;
86
case EM_X86_64:
87
pch.ch_machine = IMAGE_FILE_MACHINE_AMD64;
88
break;
89
default:
90
pch.ch_machine = IMAGE_FILE_MACHINE_UNKNOWN;
91
break;
92
}
93
if (elftc_timestamp(&timestamp) != 0)
94
err(EXIT_FAILURE, "elftc_timestamp");
95
pch.ch_timestamp = (uint32_t) timestamp;
96
if (pe_update_coff_header(pe, &pch) < 0)
97
err(EXIT_FAILURE, "pe_update_coff_header() failed");
98
99
/* Setup PE optional header. */
100
memset(&poh, 0, sizeof(poh));
101
if (ecp->otf == ETF_EFI)
102
poh.oh_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
103
poh.oh_entry = (uint32_t) eh.e_entry;
104
105
/*
106
* Default section alignment and file alignment. (Here the
107
* section alignment is set to the default page size of the
108
* archs supported. We should use different section alignment
109
* for some arch. (e.g. IA64)
110
*/
111
poh.oh_secalign = 0x1000;
112
poh.oh_filealign = 0x200;
113
114
/* Copy sections. */
115
scn = NULL;
116
while ((scn = elf_nextscn(e, scn)) != NULL) {
117
118
/*
119
* Read in ELF section.
120
*/
121
122
if (gelf_getshdr(scn, &sh) == NULL) {
123
warnx("gelf_getshdr() failed: %s", elf_errmsg(-1));
124
(void) elf_errno();
125
continue;
126
}
127
if ((name = elf_strptr(e, indx, sh.sh_name)) ==
128
NULL) {
129
warnx("elf_strptr() failed: %s", elf_errmsg(-1));
130
(void) elf_errno();
131
continue;
132
}
133
134
/* Skip sections unneeded. */
135
if (strcmp(name, ".shstrtab") == 0 ||
136
strcmp(name, ".symtab") == 0 ||
137
strcmp(name, ".strtab") == 0)
138
continue;
139
140
if ((d = elf_getdata(scn, NULL)) == NULL) {
141
warnx("elf_getdata() failed: %s", elf_errmsg(-1));
142
(void) elf_errno();
143
continue;
144
}
145
146
if (strcmp(name, ".text") == 0) {
147
poh.oh_textbase = (uint32_t) sh.sh_addr;
148
poh.oh_textsize = (uint32_t) roundup(sh.sh_size,
149
poh.oh_filealign);
150
} else {
151
if (po == PE_O_PE32 && strcmp(name, ".data") == 0)
152
poh.oh_database = sh.sh_addr;
153
if (sh.sh_type == SHT_NOBITS)
154
poh.oh_bsssize += (uint32_t)
155
roundup(sh.sh_size, poh.oh_filealign);
156
else if (sh.sh_flags & SHF_ALLOC)
157
poh.oh_datasize += (uint32_t)
158
roundup(sh.sh_size, poh.oh_filealign);
159
}
160
161
/*
162
* Create PE/COFF section.
163
*/
164
165
if ((ps = pe_newscn(pe)) == NULL) {
166
warn("pe_newscn() failed");
167
continue;
168
}
169
170
/*
171
* Setup PE/COFF section header. The section name is not
172
* NUL-terminated if its length happens to be 8. Long
173
* section name should be truncated for PE image according
174
* to the PE/COFF specification.
175
*/
176
memset(&psh, 0, sizeof(psh));
177
strncpy(psh.sh_name, name, sizeof(psh.sh_name));
178
psh.sh_addr = sh.sh_addr;
179
psh.sh_virtsize = sh.sh_size;
180
if (sh.sh_type != SHT_NOBITS)
181
psh.sh_rawsize = roundup(sh.sh_size, poh.oh_filealign);
182
else
183
psh.sh_char |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
184
185
/*
186
* Translate ELF section flags to PE/COFF section flags.
187
*/
188
psh.sh_char |= IMAGE_SCN_MEM_READ;
189
if (sh.sh_flags & SHF_WRITE)
190
psh.sh_char |= IMAGE_SCN_MEM_WRITE;
191
if (sh.sh_flags & SHF_EXECINSTR)
192
psh.sh_char |= IMAGE_SCN_MEM_EXECUTE |
193
IMAGE_SCN_CNT_CODE;
194
if ((sh.sh_flags & SHF_ALLOC) && (psh.sh_char & 0xF0) == 0)
195
psh.sh_char |= IMAGE_SCN_CNT_INITIALIZED_DATA;
196
197
/* Mark relocation section "discardable". */
198
if (strcmp(name, ".reloc") == 0)
199
psh.sh_char |= IMAGE_SCN_MEM_DISCARDABLE;
200
201
if (pe_update_section_header(ps, &psh) < 0) {
202
warn("pe_update_section_header() failed");
203
continue;
204
}
205
206
/* Copy section content. */
207
if ((pb = pe_newbuffer(ps)) == NULL) {
208
warn("pe_newbuffer() failed");
209
continue;
210
}
211
pb->pb_align = 1;
212
pb->pb_off = 0;
213
if (sh.sh_type != SHT_NOBITS) {
214
pb->pb_size = roundup(sh.sh_size, poh.oh_filealign);
215
if ((pb->pb_buf = calloc(1, pb->pb_size)) == NULL) {
216
warn("calloc failed");
217
continue;
218
}
219
memcpy(pb->pb_buf, d->d_buf, sh.sh_size);
220
}
221
}
222
elferr = elf_errno();
223
if (elferr != 0)
224
warnx("elf_nextscn() failed: %s", elf_errmsg(elferr));
225
226
/* Update PE optional header. */
227
if (pe_update_opt_header(pe, &poh) < 0)
228
err(EXIT_FAILURE, "pe_update_opt_header() failed");
229
230
/* Write out PE/COFF object. */
231
if (pe_update(pe) < 0)
232
err(EXIT_FAILURE, "pe_update() failed");
233
234
pe_finish(pe);
235
elf_end(e);
236
}
237
238